/* * Copyright (C) 2010 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. */ /** * \file phDalNfc.c * \brief DAL Implementation for linux * * Project: Trusted NFC Linux Lignt * * $Date: 07 aug 2009 * $Author: Jonathan roux * $Revision: 1.0 $ * */ #define _DAL_4_NFC_C #include #include #ifdef ANDROID #include #else #include #endif #include #include #include #include #include #include #include #include #include /*----------------------------------------------------------------------------------- MISC DEFINITIONS ------------------------------------------------------------------------------------*/ #define DEFAULT_LINK_TYPE ENUM_DAL_LINK_TYPE_COM1 /*----------------------------------------------------------------------------------- TYPES ------------------------------------------------------------------------------------*/ /*structure holds members related for both read and write operations*/ typedef struct Dal_RdWr_st { /* Read members */ pthread_t nReadThread; /* Read thread Hanlde */ pthread_mutex_t nReadEventMutex; /* Mutex to signal a read has been requested */ uint8_t * pReadBuffer; /* Read local buffer */ int nNbOfBytesToRead; /* Number of bytes to read */ int nNbOfBytesRead; /* Number of read bytes */ char nReadBusy; /* Read state machine */ char nReadThreadAlive; /* Read state machine */ char nWaitingOnRead; /* Read state machine */ /* Read wait members */ pthread_mutex_t nReadCancelEventMutex; /* Mutex to signal a read cancel has been requested */ uint8_t * pReadWaitBuffer; /* Read wait local Buffer */ int nNbOfBytesToReadWait; /* Number of bytes to read */ int nNbOfBytesReadWait; /* Number of read bytes */ char nReadWaitBusy; /* Read state machine */ char nWaitingOnReadWait; /* Read state machine */ char nCancelReadWait; /* Read state machine */ /* Write members */ pthread_t nWriteThread; /* Write thread Hanlde */ pthread_mutex_t nWriteEventMutex; /* Mutex to signal a write has been requested */ uint8_t * pWriteBuffer; /* Write local buffer */ int nNbOfBytesToWrite; /* Number of bytes to write */ int nNbOfBytesWritten; /* Number of bytes written */ char nWaitingOnWrite; /* Write state machine */ char nWriteThreadAlive; /* Write state machine */ char nWriteBusy; /* Write state machine */ } phDal4Nfc_RdWr_t; typedef void (*pphDal4Nfc_DeferFuncPointer_t) (void * ); typedef void * (*pphDal4Nfc_thread_handler_t) (void * pParam); /*----------------------------------------------------------------------------------- VARIABLES ------------------------------------------------------------------------------------*/ static phDal4Nfc_RdWr_t gReadWriteContext; static phDal4Nfc_SContext_t gDalContext; static pphDal4Nfc_SContext_t pgDalContext; static phHal_sHwReference_t * pgDalHwContext; static pthread_mutex_t nCriticalSectionMutex; static pthread_mutex_t nThreadsEventMutex; #ifdef USE_MQ_MESSAGE_QUEUE static phDal4Nfc_DeferredCall_Msg_t nDeferedMessage; static mqd_t nDeferedCallMessageQueueId; #else int nDeferedCallMessageQueueId = 0; #endif static phDal4Nfc_link_cbk_interface_t gLinkFunc; /*----------------------------------------------------------------------------------- PROTOTYPES ------------------------------------------------------------------------------------*/ static void phDal4Nfc_DeferredCb (void *params); static NFCSTATUS phDal4Nfc_StartThreads (void); static void phDal4Nfc_FillMsg (phDal4Nfc_Message_t *pDalMsg, phOsalNfc_Message_t *pOsalMsg); /*----------------------------------------------------------------------------------- DAL API IMPLEMENTATION ------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_Register PURPOSE: DAL register function. -----------------------------------------------------------------------------*/ NFCSTATUS phDal4Nfc_Register( phNfcIF_sReference_t *psRefer, phNfcIF_sCallBack_t if_cb, void *psIFConf ) { NFCSTATUS result = NFCSTATUS_SUCCESS; if ((NULL != psRefer) && (NULL != psRefer->plower_if) && (NULL != if_cb.receive_complete) && (NULL != if_cb.send_complete) ) { /* Register the LLC functions to the upper layer */ psRefer->plower_if->init = phDal4Nfc_Init; psRefer->plower_if->release = phDal4Nfc_Shutdown; psRefer->plower_if->send = phDal4Nfc_Write; psRefer->plower_if->receive = phDal4Nfc_Read; psRefer->plower_if->receive_wait = phDal4Nfc_ReadWait; psRefer->plower_if->transact_abort = phDal4Nfc_ReadWaitCancel; psRefer->plower_if->unregister = phDal4Nfc_Unregister; if (NULL != pgDalContext) { /* Copy the DAL context to the upper layer */ psRefer->plower_if->pcontext = pgDalContext; /* Register the callback function from the upper layer */ pgDalContext->cb_if.receive_complete = if_cb.receive_complete; pgDalContext->cb_if.send_complete = if_cb.send_complete; pgDalContext->cb_if.notify = if_cb.notify; /* Get the upper layer context */ pgDalContext->cb_if.pif_ctxt = if_cb.pif_ctxt; /* Update the error state */ result = NFCSTATUS_SUCCESS; } else { result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_NOT_INITIALISED); } } else /*Input parameters invalid*/ { result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_PARAMETER); } return result; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_Unregister PURPOSE: DAL unregister function. -----------------------------------------------------------------------------*/ NFCSTATUS phDal4Nfc_Unregister(void *pContext, void *pHwRef ) { NFCSTATUS result = NFCSTATUS_SUCCESS; if ((NULL == pContext) && (NULL == pHwRef)) { result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_PARAMETER); } else { if (NULL != pgDalContext) { /* Register the callback function from the upper layer */ pgDalContext->cb_if.receive_complete = NULL; pgDalContext->cb_if.send_complete = NULL ; pgDalContext->cb_if.notify = NULL ; /* Get the upper layer context */ pgDalContext->cb_if.pif_ctxt = NULL ; // pgDalContext = NULL; } else { result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_NOT_INITIALISED); } } return result; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_Init PURPOSE: DAL Init function. -----------------------------------------------------------------------------*/ NFCSTATUS phDal4Nfc_Init(void *pContext, void *pHwRef ) { NFCSTATUS result = NFCSTATUS_SUCCESS; if ((NULL != pContext) && (NULL != pHwRef)) { pContext = pgDalContext; pgDalHwContext = (phHal_sHwReference_t *)pHwRef; if ( gDalContext.hw_valid == TRUE ) { /* The link has been opened from the application interface */ gLinkFunc.open_from_handle(pgDalHwContext); if (!gLinkFunc.is_opened()) { result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE); } else { /* Clear link buffers */ gLinkFunc.flush(); } } else { static phDal4Nfc_sConfig_t hw_config; hw_config.nLinkType = DEFAULT_LINK_TYPE; result = phDal4Nfc_Config(&hw_config, pHwRef ); } } else /*Input parametrs invalid*/ { result = NFCSTATUS_INVALID_PARAMETER; } return result; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_Shutdown PURPOSE: DAL Shutdown function. -----------------------------------------------------------------------------*/ NFCSTATUS phDal4Nfc_Shutdown( void *pContext, void *pHwRef) { NFCSTATUS result = NFCSTATUS_SUCCESS; void * pThreadReturn; // if (pContext == NULL) // return NFCSTATUS_INVALID_PARAMETER; if (gDalContext.hw_valid == TRUE) { /* Flush the link */ gLinkFunc.flush(); /* Kill the read and write threads */ // gReadWriteContext.nReadThreadAlive = 0; // gReadWriteContext.nWriteThreadAlive = 0; // pthread_mutex_unlock(&gReadWriteContext.nReadEventMutex); // pthread_mutex_unlock(&gReadWriteContext.nWriteEventMutex); // if (pthread_join(gReadWriteContext.nReadThread, &pThreadReturn) != 0) // { // result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED); // } // if (pthread_join(gReadWriteContext.nWriteThread, &pThreadReturn) != 0) // { // result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED); // } /* Close the message queue */ #ifdef USE_MQ_MESSAGE_QUEUE mq_close(nDeferedCallMessageQueueId); #endif /* Destroy the mutexes */ // pthread_mutex_destroy(&gReadWriteContext.nReadEventMutex); // pthread_mutex_destroy(&gReadWriteContext.nReadCancelEventMutex); // pthread_mutex_destroy(&gReadWriteContext.nWriteEventMutex); // pthread_mutex_destroy(&nCriticalSectionMutex); // pthread_mutex_destroy(&nThreadsEventMutex); /* Close the link */ // gLinkFunc.close(); /* Reset the Writer Thread values to NULL */ // memset((void *)&gReadWriteContext,0,sizeof(gReadWriteContext)); /* Reset the DAL context values to NULL */ // memset((void *)&gDalContext,0,sizeof(gDalContext)); } // gDalContext.hw_valid = FALSE; return result; } NFCSTATUS phDal4Nfc_ConfigRelease( void *pHwRef) { NFCSTATUS result = NFCSTATUS_SUCCESS; void * pThreadReturn; if (gDalContext.hw_valid == TRUE) { /* Flush the link */ gLinkFunc.flush(); /* Kill the read and write threads */ gReadWriteContext.nReadThreadAlive = 0; gReadWriteContext.nWriteThreadAlive = 0; pthread_mutex_unlock(&gReadWriteContext.nReadEventMutex); pthread_mutex_unlock(&gReadWriteContext.nWriteEventMutex); if (pthread_join(gReadWriteContext.nReadThread, &pThreadReturn) != 0) { result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED); DAL_PRINT("phDal4Nfc_ConfigRelease KO"); } if (pthread_join(gReadWriteContext.nWriteThread, &pThreadReturn) != 0) { result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED); DAL_PRINT("phDal4Nfc_ConfigRelease KO"); } /* Close the message queue */ #ifdef USE_MQ_MESSAGE_QUEUE mq_close(nDeferedCallMessageQueueId); #endif /* Destroy the mutexes */ pthread_mutex_destroy(&gReadWriteContext.nReadEventMutex); pthread_mutex_destroy(&gReadWriteContext.nReadCancelEventMutex); pthread_mutex_destroy(&gReadWriteContext.nWriteEventMutex); pthread_mutex_destroy(&nCriticalSectionMutex); pthread_mutex_destroy(&nThreadsEventMutex); /* Close the link */ gLinkFunc.close(); /* Reset the Writer Thread values to NULL */ memset((void *)&gReadWriteContext,0,sizeof(gReadWriteContext)); /* Reset the DAL context values to NULL */ memset((void *)&gDalContext,0,sizeof(gDalContext)); } gDalContext.hw_valid = FALSE; DAL_DEBUG("phDal4Nfc_ConfigRelease(): %04x\n", result); return result; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_Write PURPOSE: DAL Write function. -----------------------------------------------------------------------------*/ NFCSTATUS phDal4Nfc_Write( void *pContext, void *pHwRef,uint8_t *pBuffer, uint16_t length) { NFCSTATUS result = NFCSTATUS_SUCCESS; if ((NULL != pContext) && (NULL != pHwRef)&& (NULL != pBuffer) && (0 != length)) { if( gDalContext.hw_valid== TRUE) { if((!gReadWriteContext.nWriteBusy)&& (!gReadWriteContext.nWaitingOnWrite)) { DAL_DEBUG("phDal4Nfc_Write(): %d\n", length); /* Make a copy of the passed arguments */ gReadWriteContext.pWriteBuffer = pBuffer; gReadWriteContext.nNbOfBytesToWrite = length; /* Change the write state so that thread can take over the write */ gReadWriteContext.nWriteBusy = TRUE; /* Just set variable here. This is the trigger for the Write thread */ gReadWriteContext.nWaitingOnWrite = TRUE; /* Update the error state */ result = NFCSTATUS_PENDING; pthread_mutex_unlock(&gReadWriteContext.nWriteEventMutex); } else { /* Driver is BUSY with previous Write */ DAL_PRINT("phDal4Nfc_Write() : Busy \n"); result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_BUSY) ; } } else { /* TBD :Additional error code : NOT_INITIALISED */ result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE); } }/*end if-Input parametrs valid-check*/ else { result = NFCSTATUS_INVALID_PARAMETER; } return result; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_Read PURPOSE: DAL Read function. -----------------------------------------------------------------------------*/ NFCSTATUS phDal4Nfc_Read( void *pContext, void *pHwRef,uint8_t *pBuffer, uint16_t length) { NFCSTATUS result = NFCSTATUS_SUCCESS; if ((NULL != pContext) && (NULL != pHwRef)&& (NULL != pBuffer) && (0 != length)) { if ( gDalContext.hw_valid== TRUE) { if((!gReadWriteContext.nReadBusy)&& (!gReadWriteContext.nWaitingOnRead)) { DAL_DEBUG("*****DAl Read called length : %d\n", length); /* Make a copy of the passed arguments */ gReadWriteContext.pReadBuffer = pBuffer; gReadWriteContext.nNbOfBytesToRead = length; /* Change the Read state so that thread can take over the read */ gReadWriteContext.nReadBusy = TRUE; /* Just set variable here. This is the trigger for the Reader thread */ gReadWriteContext.nWaitingOnRead = TRUE; // retval = ResetEvent(gReadWriteContext.nReadCancelEventMutex); /* TO DO */ /* Update the erro state */ result = NFCSTATUS_PENDING; pthread_mutex_unlock(&gReadWriteContext.nReadEventMutex); } else { /* Driver is BUSY with prev Read */ DAL_PRINT("DAL BUSY\n"); /* Make a copy of the passed arguments */ gReadWriteContext.pReadBuffer = pBuffer; gReadWriteContext.nNbOfBytesToRead = length; result = NFCSTATUS_PENDING; pthread_mutex_unlock(&gReadWriteContext.nReadEventMutex); } } else { /* TBD :Additional error code : NOT_INITIALISED */ result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE); } }/*end if-Input parametrs valid-check*/ else { result = NFCSTATUS_INVALID_PARAMETER; } DAL_DEBUG("*****DAl Read called result : %x\n", result); return result; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_ReadWait PURPOSE: DAL Read wait function. -----------------------------------------------------------------------------*/ NFCSTATUS phDal4Nfc_ReadWait(void *pContext, void *pHwRef,uint8_t *pBuffer, uint16_t length) { NFCSTATUS result = NFCSTATUS_SUCCESS; if ((NULL != pContext) && (NULL != pHwRef)&& (NULL != pBuffer) && (0 != length)) { if ( gDalContext.hw_valid== TRUE) { if((!gReadWriteContext.nReadBusy)&& (!gReadWriteContext.nReadWaitBusy)&& (!gReadWriteContext.nWaitingOnRead)) { /* Save the copy of passed arguments */ gReadWriteContext.pReadWaitBuffer = pBuffer; gReadWriteContext.nNbOfBytesToReadWait = length; /* Change the Read state so that thread can take over the read */ gReadWriteContext.nReadWaitBusy = TRUE; /* Just set variable here. This is the trigger for the Reader thread */ gReadWriteContext.nWaitingOnReadWait = TRUE; /* Update the error state */ result = NFCSTATUS_SUCCESS; } else { /* Driver is BUSY with prev Read */ result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_BUSY); } } else { /* TBD :Additional error code : NOT_INITIALISED */ result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE); } }/*end if -Input parametrs valid-check*/ else { result = NFCSTATUS_INVALID_PARAMETER; } return result; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_ReadWaitCancel PURPOSE: Cancel the Read wait function. -----------------------------------------------------------------------------*/ NFCSTATUS phDal4Nfc_ReadWaitCancel( void *pContext, void *pHwRef) { #if 0 char retval; NFCSTATUS result = NFCSTATUS_SUCCESS; DAL_PRINT("DAl Read cancel called \n"); if ((NULL != pContext) && (NULL != pHwRef)) { if ( gDalContext.hw_valid== TRUE) { /* Clear The Comm Port Event */ if (!SetCommMask(h_serial_port, 0x0000)) { /* Windows Error */ result = NFCSTATUS_BOARD_COMMUNICATION_ERROR; } /* Cancel the Wait read */ retval = SetEvent(gReadWriteContext.nReadCancelEventMutex); } else { result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE); } } else { result = NFCSTATUS_INVALID_PARAMETER; } return result; #endif return 0; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_Config PURPOSE: Configure the serial port. -----------------------------------------------------------------------------*/ NFCSTATUS phDal4Nfc_Config(pphDal4Nfc_sConfig_t config,void **phwref) { NFCSTATUS retstatus = NFCSTATUS_SUCCESS; DAL_PRINT("phDal4Nfc_Config"); if ((config == NULL) || (phwref == NULL) || (config->nClientId == -1)) return NFCSTATUS_INVALID_PARAMETER; /* Register the link callbacks */ memset(&gLinkFunc, 0, sizeof(phDal4Nfc_link_cbk_interface_t)); switch(config->nLinkType) { case ENUM_DAL_LINK_TYPE_COM1: case ENUM_DAL_LINK_TYPE_COM2: case ENUM_DAL_LINK_TYPE_COM3: case ENUM_DAL_LINK_TYPE_COM4: case ENUM_DAL_LINK_TYPE_COM5: case ENUM_DAL_LINK_TYPE_USB: { /* Uart link interface */ gLinkFunc.init = phDal4Nfc_uart_initialize; gLinkFunc.open_from_handle = phDal4Nfc_uart_set_open_from_handle; gLinkFunc.is_opened = phDal4Nfc_uart_is_opened; gLinkFunc.flush = phDal4Nfc_uart_flush; gLinkFunc.close = phDal4Nfc_uart_close; gLinkFunc.open_and_configure = phDal4Nfc_uart_open_and_configure; gLinkFunc.read = phDal4Nfc_uart_read; gLinkFunc.write = phDal4Nfc_uart_write; } break; case ENUM_DAL_LINK_TYPE_I2C: { /* Uart link interface */ gLinkFunc.init = phDal4Nfc_i2c_initialize; gLinkFunc.open_from_handle = phDal4Nfc_i2c_set_open_from_handle; gLinkFunc.is_opened = phDal4Nfc_i2c_is_opened; gLinkFunc.flush = phDal4Nfc_i2c_flush; gLinkFunc.close = phDal4Nfc_i2c_close; gLinkFunc.open_and_configure = phDal4Nfc_i2c_open_and_configure; gLinkFunc.read = phDal4Nfc_i2c_read; gLinkFunc.write = phDal4Nfc_i2c_write; break; } default: { /* Shound not happen : Bad parameter */ return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_PARAMETER); } } gLinkFunc.init(); /* So that link interface can initialize its internal state */ retstatus = gLinkFunc.open_and_configure(config, phwref); if (retstatus != NFCSTATUS_SUCCESS) return retstatus; /* Iniatilize the DAL context */ (void)memset(&gDalContext,0,sizeof(phDal4Nfc_SContext_t)); pgDalContext = &gDalContext; /* Reset the Writer Thread values to NULL */ memset((void *)&gReadWriteContext,0,sizeof(gReadWriteContext)); gReadWriteContext.nReadThreadAlive = TRUE; gReadWriteContext.nWriteThreadAlive = TRUE; /* Reset the Reader Thread values to NULL */ memset((void *)&gReadWriteContext,0,sizeof(gReadWriteContext)); gReadWriteContext.nReadThreadAlive = TRUE; gReadWriteContext.nWriteThreadAlive = TRUE; pthread_mutex_init (&gReadWriteContext.nReadEventMutex, NULL); pthread_mutex_init (&gReadWriteContext.nReadCancelEventMutex, NULL); pthread_mutex_init (&gReadWriteContext.nWriteEventMutex, NULL); /* Prepare the message queue for the defered calls */ #ifdef USE_MQ_MESSAGE_QUEUE nDeferedCallMessageQueueId = mq_open(MQ_NAME_IDENTIFIER, O_CREAT|O_RDWR, 0666, &MQ_QUEUE_ATTRIBUTES); #else nDeferedCallMessageQueueId = config->nClientId; #endif /* Start Read and Write Threads */ if(NFCSTATUS_SUCCESS != phDal4Nfc_StartThreads()) { return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED); } gDalContext.hw_valid = TRUE; return NFCSTATUS_SUCCESS; } /*----------------------------------------------------------------------------------- DAL INTERNAL IMPLEMENTATION ------------------------------------------------------------------------------------*/ /** * \ingroup grp_nfc_dal * * \brief DAL Reader thread handler * This function manages the reads from the link interface. The reads are done from * this thread to create the asynchronous mecanism. When calling the synchronous * function phDal4Nfc_Read, the nWaitingOnRead mutex is unlocked and the read * can be done. Then a client callback is called to send the result. * * \param[in] pArg A custom argument that can be passed to the thread (not used) * * \retval TRUE Thread exiting. */ int phDal4Nfc_ReaderThread(void * pArg) { char retvalue; NFCSTATUS result = NFCSTATUS_SUCCESS; uint8_t retry_cnt=0; void * memsetRet; static int MsgType= PHDAL4NFC_READ_MESSAGE; int * pmsgType=&MsgType; phDal4Nfc_Message_t sMsg; phOsalNfc_Message_t OsalMsg ; int i; pthread_setname_np(pthread_self(), "reader"); /* Create the overlapped event. Must be closed before exiting to avoid a handle leak. This event is used READ API and the Reader thread*/ pthread_mutex_unlock(&nThreadsEventMutex); /* To indicate thread is ready */ DAL_PRINT("RX Thread \n"); while(gReadWriteContext.nReadThreadAlive) /* Thread Loop */ { retvalue = 1; gReadWriteContext.nWaitingOnRead = ((gReadWriteContext.nWaitingOnRead == 1)?1:0); gReadWriteContext.nCancelReadWait = 0; gReadWriteContext.nWaitingOnReadWait = 0; pthread_mutex_lock(&gReadWriteContext.nReadEventMutex); /* Remains locked till we get a read request */ /* Check for the read request from user */ if (gReadWriteContext.nWaitingOnRead) { /* Issue read operation.*/ gReadWriteContext.nNbOfBytesRead=0; DAL_DEBUG("\n*New *** *****Request Length = %d",gReadWriteContext.nNbOfBytesToRead); memsetRet=memset(gReadWriteContext.pReadBuffer,0,gReadWriteContext.nNbOfBytesToRead); /* Wait for Write Completion */ usleep(2500); gReadWriteContext.nNbOfBytesRead = gLinkFunc.read(gReadWriteContext.pReadBuffer, gReadWriteContext.nNbOfBytesToRead); if (gReadWriteContext.nNbOfBytesRead == -1) { DAL_DEBUG("Read failed\n", 0); /* TBD : Error, report it.*/ result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_BOARD_COMMUNICATION_ERROR); } /* End of File Read if */ else if (gReadWriteContext.nNbOfBytesRead == 0) { /* In case of timeout, keep polling */ pthread_mutex_unlock(&gReadWriteContext.nReadEventMutex); continue; } else { DAL_DEBUG("Read ok. nbToRead=%d\n", gReadWriteContext.nNbOfBytesToRead); DAL_DEBUG("NbReallyRead=%d\n", gReadWriteContext.nNbOfBytesRead); DAL_PRINT("ReadBuff[]={ "); for (i = 0; i < gReadWriteContext.nNbOfBytesRead; i++) { DAL_DEBUG("0x%x ", gReadWriteContext.pReadBuffer[i]); } DAL_PRINT("}\n"); /* read completed immediately */ sMsg.eMsgType= PHDAL4NFC_READ_MESSAGE; /* Update the state */ phDal4Nfc_FillMsg(&sMsg,&OsalMsg); phDal4Nfc_DeferredCall((pphDal4Nfc_DeferFuncPointer_t)phDal4Nfc_DeferredCb,(void *)pmsgType); memsetRet=memset(&sMsg,0,sizeof(phDal4Nfc_Message_t)); memsetRet=memset(&OsalMsg,0,sizeof(phOsalNfc_Message_t)); } } else if (gReadWriteContext.nWaitingOnReadWait) /* Wait Read Loop */ { gReadWriteContext.nNbOfBytesReadWait = gLinkFunc.read(gReadWriteContext.pReadWaitBuffer, gReadWriteContext.nNbOfBytesToReadWait); if (gReadWriteContext.nNbOfBytesReadWait == -1) { /* Error; report it.*/ result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_BOARD_COMMUNICATION_ERROR); } else { sMsg.eMsgType= PHDAL4NFC_READWAIT_MESSAGE; phDal4Nfc_FillMsg(&sMsg,&OsalMsg); retry_cnt=0; /* Update the state */ gReadWriteContext.nReadBusy = FALSE; /* Reset flag so that another opertion can be issued.*/ gReadWriteContext.nWaitingOnRead = FALSE; gReadWriteContext.nNbOfBytesRead=0; gReadWriteContext.nNbOfBytesToRead=0; phDal4Nfc_DeferredCall((pphDal4Nfc_DeferFuncPointer_t) phDal4Nfc_DeferredCb,(void *)pmsgType); /* Update the state */ gReadWriteContext.nReadWaitBusy = FALSE; /* Reset flag so that another opertion can be issued.*/ gReadWriteContext.nWaitingOnReadWait = FALSE; }/*end-else*/ } else if (gReadWriteContext.nCancelReadWait) { DAL_PRINT("Read Wait is Canceled\n"); } else if ( result != NFCSTATUS_SUCCESS ) { /* Report it to user */ sMsg.transactInfo.status = result; /*map to OSAL msg format*/ OsalMsg.eMsgType = PH_DAL4NFC_MESSAGE_BASE; OsalMsg.pMsgData = (void*)&sMsg; /* Update the state */ gReadWriteContext.nNbOfBytesRead=0; gReadWriteContext.nNbOfBytesToRead=0; phDal4Nfc_DeferredCall((pphDal4Nfc_DeferFuncPointer_t) phDal4Nfc_DeferredCb,(void *)pmsgType); } /*end-else if ( result != NFCSTATUS_SUCCESS )*/ else { continue; } } /* End of thread Loop*/ return TRUE; } /** * \ingroup grp_nfc_dal * * \brief DAL Writer thread handler * This function manages the writes to the link interface. The writes are done from * this thread to create the asynchronous mecanism. When calling the synchronous * function phDal4Nfc_Write, the nWaitingOnWrite mutex is unlocked and the write * can be done. Then a client callback is called to signal the operation as complete. * * \param[in] pArg A custom argument that can be passed to the thread (not used) * * \retval TRUE Thread exiting. */ int phDal4Nfc_WriterThread(void * pArg) { char retvalue = 1; NFCSTATUS result = NFCSTATUS_SUCCESS; phDal4Nfc_Message_t sMsg; phOsalNfc_Message_t OsalMsg ; static int MsgType=PHDAL4NFC_WRITE_MESSAGE; int * pmsgType=&MsgType; int i; pthread_setname_np(pthread_self(), "writer"); /* Create the overlapped event. Must be closed before exiting to avoid a handle leak. This event is used READ API and the Reader thread*/ pthread_mutex_unlock(&nThreadsEventMutex); /* To indicate thread is ready */ /* Set the thread started Event, to make sure that both threads are ready in the initialization state*/ while(gReadWriteContext.nWriteThreadAlive) /* Thread Loop */ { retvalue = 1; DAL_PRINT("TX Started\n"); pthread_mutex_lock(&gReadWriteContext.nWriteEventMutex); /* Remains locked till we get a write request */ /* Check for the write request from user */ if(gReadWriteContext.nWaitingOnWrite) { /* Issue a write after a 8ms pause */ usleep(8000); gReadWriteContext.nNbOfBytesWritten = gLinkFunc.write(gReadWriteContext.pWriteBuffer, gReadWriteContext.nNbOfBytesToWrite); if (gReadWriteContext.nNbOfBytesWritten != gReadWriteContext.nNbOfBytesToWrite) { /* controller may be in standby. do it again! */ usleep(8000); gReadWriteContext.nNbOfBytesWritten = gLinkFunc.write(gReadWriteContext.pWriteBuffer, gReadWriteContext.nNbOfBytesToWrite); } if (gReadWriteContext.nNbOfBytesWritten != gReadWriteContext.nNbOfBytesToWrite) { /* Report write failure or timeout */ DAL_DEBUG("Write error in write thread\n", 0); result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_BOARD_COMMUNICATION_ERROR); }/*end writeFile*/ else /* Results ready */ { /* Write operation completed successfully.*/ sMsg.eMsgType = PHDAL4NFC_WRITE_MESSAGE; //sMsg.pContext = pgDalContext; sMsg.pContext= pgDalContext->cb_if.pif_ctxt; phDal4Nfc_FillMsg(&sMsg,&OsalMsg); /* Post a message to the HAL Thread */ /* Update the state */ gReadWriteContext.nWriteBusy = FALSE; /* Reset flag so that another opertion can be issued.*/ gReadWriteContext.nWaitingOnWrite = FALSE; gReadWriteContext.nNbOfBytesWritten=gReadWriteContext.nNbOfBytesToWrite; DAL_DEBUG("NON Overlapped Write :DAl Writer thread called length : %d\n", gReadWriteContext.nNbOfBytesWritten); DAL_PRINT("WriteBuff[]={ "); for (i = 0; i < gReadWriteContext.nNbOfBytesWritten; i++) { DAL_DEBUG("0x%x ", gReadWriteContext.pWriteBuffer[i]); } DAL_PRINT("}\n"); phDal4Nfc_DeferredCall(phDal4Nfc_DeferredCb,pmsgType); }/*end else Results ready */ } else if ( result != NFCSTATUS_SUCCESS ) { /* Report it to user */ sMsg.transactInfo.status = result; /*map to OSAL msg format*/ OsalMsg.eMsgType = PH_DAL4NFC_MESSAGE_BASE; OsalMsg.pMsgData = (void*)&sMsg; /* Update the state */ gReadWriteContext.nWriteBusy = FALSE; /* Reset flag so that another opertion can be issued.*/ gReadWriteContext.nWaitingOnWrite = FALSE; gReadWriteContext.nNbOfBytesWritten = 0; DAL_DEBUG("DAl Writer thread error called length : %d\n", gReadWriteContext.nNbOfBytesWritten); }/*end elseif*/ else { continue; } }/* End of thread Loop*/ return TRUE; } /** * \ingroup grp_nfc_dal * * \brief DAL Start threads function * This function is called from phDal4Nfc_Config and is responsible of creating the * reader and writer threads. Also it will init necessary mutexes. * * \retval NFCSTATUS_SUCCESS If success. * \retval NFCSTATUS_FAILED Can not create thread or retreive its attributes */ NFCSTATUS phDal4Nfc_StartThreads(void) { pthread_attr_t nReadThreadAttributes; pthread_attr_t nWriteThreadAttributes; int ret; /* Mutex init */ pthread_mutex_init (&nCriticalSectionMutex, NULL); pthread_mutex_init (&nThreadsEventMutex, NULL); /* Lock the request mutexes */ pthread_mutex_lock(&gReadWriteContext.nWriteEventMutex); pthread_mutex_lock(&gReadWriteContext.nReadEventMutex); pthread_mutex_lock(&nThreadsEventMutex); /* First thread ready lock */ ret = pthread_create(&gReadWriteContext.nReadThread, NULL, (pphDal4Nfc_thread_handler_t)phDal4Nfc_ReaderThread, (void*) "dal_read_thread"); if(ret != 0) return(PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED)); pthread_mutex_lock(&nThreadsEventMutex); /* Blocking lock */ // Here we have been unblocked by the thread handler. (so the thread is ready) ret = pthread_create(&gReadWriteContext.nWriteThread, NULL, (pphDal4Nfc_thread_handler_t)phDal4Nfc_WriterThread, (void*) "dal_write_thread"); if(ret != 0) return(PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED)); pthread_mutex_lock(&nThreadsEventMutex); /* Blocking lock */ // Here we have been unblocked by the thread handler. (so the thread is ready) pthread_mutex_unlock(&nThreadsEventMutex); return NFCSTATUS_SUCCESS; } /** * \ingroup grp_nfc_dal * * \brief DAL fill message function * Internal messages management. This function fills message structure * depending on message types. * * \param[in, out] pDalMsg DAL message to fill * \param[in, out] pOsalMsg OSAL message to fill * */ void phDal4Nfc_FillMsg(phDal4Nfc_Message_t *pDalMsg,phOsalNfc_Message_t *pOsalMsg) { if(NULL != pgDalHwContext) { if(pDalMsg->eMsgType == PHDAL4NFC_WRITE_MESSAGE) { pDalMsg->transactInfo.length = (uint8_t)gReadWriteContext.nNbOfBytesWritten; pDalMsg->transactInfo.buffer = NULL; pDalMsg->transactInfo.status = NFCSTATUS_SUCCESS; pDalMsg->pHwRef = pgDalHwContext; pDalMsg->writeCbPtr = pgDalContext->cb_if.send_complete; pOsalMsg->eMsgType = PH_DAL4NFC_MESSAGE_BASE; pOsalMsg->pMsgData = pDalMsg; return; } else if(pDalMsg->eMsgType == PHDAL4NFC_READ_MESSAGE) { pDalMsg->transactInfo.length = (uint8_t)gReadWriteContext.nNbOfBytesRead; pDalMsg->transactInfo.buffer = gReadWriteContext.pReadBuffer; pDalMsg->pContext= pgDalContext->cb_if.pif_ctxt; } else { pDalMsg->transactInfo.length = (uint8_t)gReadWriteContext.nNbOfBytesReadWait; pDalMsg->transactInfo.buffer = gReadWriteContext.pReadWaitBuffer; pDalMsg->pContext= pgDalContext; } pDalMsg->transactInfo.status = NFCSTATUS_SUCCESS; pDalMsg->pHwRef = pgDalHwContext; pDalMsg->readCbPtr = pgDalContext->cb_if.receive_complete; /*map to OSAL msg format*/ pOsalMsg->eMsgType = PH_DAL4NFC_MESSAGE_BASE; pOsalMsg->pMsgData = pDalMsg; } } /** * \ingroup grp_nfc_dal * * \brief DAL deferred callback function * Generic handler function called by a client thread when reading a message from the queue. * Will function will directly call the client function (same context). See phDal4Nfc_DeferredCall * * \param[in] params Parameter that will be passed to the client function. * */ void phDal4Nfc_DeferredCb (void *params) { int* pParam=NULL; phNfc_sTransactionInfo_t TransactionInfo; pParam=(int*)params; switch(*pParam) { case PHDAL4NFC_READ_MESSAGE: DAL_PRINT(" Dal deferred read called \n"); TransactionInfo.buffer=gReadWriteContext.pReadBuffer; TransactionInfo.length=(uint16_t)gReadWriteContext.nNbOfBytesRead; TransactionInfo.status=NFCSTATUS_SUCCESS; gReadWriteContext.nReadBusy = FALSE; /* Reset flag so that another opertion can be issued.*/ gReadWriteContext.nWaitingOnRead = FALSE; if ((NULL != pgDalContext) && (NULL != pgDalContext->cb_if.receive_complete)) { pgDalContext->cb_if.receive_complete(pgDalContext->cb_if.pif_ctxt, pgDalHwContext,&TransactionInfo); } break; case PHDAL4NFC_READWAIT_MESSAGE: /*dalMsg->readCbPtr(dalMsg->pContext, dalMsg->pHwRef, &dalMsg->transactInfo);*/ break; case PHDAL4NFC_WRITE_MESSAGE: DAL_PRINT(" Dal deferred write called \n"); /* DAL_DEBUG("dalMsg->transactInfo.length : %d\n", dalMsg->transactInfo.length); */ TransactionInfo.buffer=NULL; TransactionInfo.length=(uint16_t)gReadWriteContext.nNbOfBytesWritten; TransactionInfo.status=NFCSTATUS_SUCCESS; if ((NULL != pgDalContext) && (NULL != pgDalContext->cb_if.send_complete)) { pgDalContext->cb_if.send_complete(pgDalContext->cb_if.pif_ctxt, pgDalHwContext,&TransactionInfo); } break; default: break; } } /** * \ingroup grp_nfc_dal * * \brief DAL deferred call function * This function will enable to call the callback client asyncronously and in the client context. * It will post a message in a queue that will be processed by a client thread. * * \param[in] func The function to call when message is read from the queue * \param[in] param Parameter that will be passed to the 'func' function. * */ void phDal4Nfc_DeferredCall(pphDal4Nfc_DeferFuncPointer_t func, void *param) { int retvalue = 0; phDal4Nfc_Message_Wrapper_t nDeferedMessageWrapper; phDal4Nfc_DeferredCall_Msg_t *pDeferedMessage; static phDal4Nfc_DeferredCall_Msg_t nDeferedMessageRead; static phDal4Nfc_DeferredCall_Msg_t nDeferedMessageWrite; pthread_mutex_lock(&nCriticalSectionMutex); #ifdef USE_MQ_MESSAGE_QUEUE nDeferedMessage.eMsgType = PH_DAL4NFC_MESSAGE_BASE; nDeferedMessage.def_call = func; nDeferedMessage.params = param; retvalue = (int)mq_send(nDeferedCallMessageQueueId, (char *)&nDeferedMessage, sizeof(phDal4Nfc_DeferredCall_Msg_t), 0); #else if(PHDAL4NFC_READ_MESSAGE==(* (int*)param)) { pDeferedMessage = &nDeferedMessageRead; } else { pDeferedMessage = &nDeferedMessageWrite; } nDeferedMessageWrapper.mtype = 1; nDeferedMessageWrapper.msg.eMsgType = PH_DAL4NFC_MESSAGE_BASE; pDeferedMessage->pCallback = func; pDeferedMessage->pParameter = param; nDeferedMessageWrapper.msg.pMsgData = pDeferedMessage; nDeferedMessageWrapper.msg.Size = sizeof(phDal4Nfc_DeferredCall_Msg_t); retvalue = phDal4Nfc_msgsnd(nDeferedCallMessageQueueId, (struct msgbuf *)&nDeferedMessageWrapper, sizeof(phLibNfc_Message_t), 0); #endif pthread_mutex_unlock(&nCriticalSectionMutex); } #undef _DAL_4_NFC_C