blob: 40864340d5494dd34c572a8e598abe20729fb0b1 [file] [log] [blame]
/*
* 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 <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#ifdef ANDROID
#include <linux/ipc.h>
#include <cutils/log.h>
#include <cutils/properties.h> // for property_get
#else
#include <sys/msg.h>
#endif
#include <semaphore.h>
#include <phDal4Nfc.h>
#include <phOsalNfc.h>
#include <phNfcStatus.h>
#include <phDal4Nfc_DeferredCall.h>
#include <phDal4Nfc_debug.h>
#include <phDal4Nfc_uart.h>
#include <phDal4Nfc_i2c.h>
#include <phDal4Nfc_link.h>
#include <phDal4Nfc_messageQueueLib.h>
#include <hardware/hardware.h>
#include <hardware/nfc.h>
/*-----------------------------------------------------------------------------------
TYPES
------------------------------------------------------------------------------------*/
/*structure holds members related for both read and write operations*/
typedef struct Dal_RdWr_st
{
/* Read members */
pthread_t nReadThread; /* Read thread Hanlde */
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 */
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 */
uint8_t * pWriteBuffer; /* Write local buffer */
uint8_t * pTempWriteBuffer; /* Temp 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 sem_t nfc_read_sem;
static int low_level_traces;
#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
------------------------------------------------------------------------------------*/
static void refresh_low_level_traces() {
#ifdef LOW_LEVEL_TRACES
low_level_traces = 1;
return;
#else
#ifdef ANDROID
char value[PROPERTY_VALUE_MAX];
property_get("ro.debuggable", value, "");
if (!value[0] || !atoi(value)) {
low_level_traces = 0; // user build, do not allow debug
return;
}
property_get("debug.nfc.LOW_LEVEL_TRACES", value, "0");
if (value[0]) {
low_level_traces = atoi(value);
return;
}
#endif
low_level_traces = 0;
#endif
}
/*-----------------------------------------------------------------------------
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 ;
}
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;
refresh_low_level_traces();
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.deviceNode = NULL;
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();
/* Close the message queue */
#ifdef USE_MQ_MESSAGE_QUEUE
mq_close(nDeferedCallMessageQueueId);
#endif
}
return result;
}
NFCSTATUS phDal4Nfc_ConfigRelease(void *pHwRef)
{
NFCSTATUS result = NFCSTATUS_SUCCESS;
void * pThreadReturn;
DAL_PRINT("phDal4Nfc_ConfigRelease ");
if (gDalContext.hw_valid == TRUE)
{
/* Signal the read and write threads to exit. NOTE: there
actually is no write thread! :) */
DAL_PRINT("Stop Reader Thread");
gReadWriteContext.nReadThreadAlive = 0;
gReadWriteContext.nWriteThreadAlive = 0;
/* Wake up the read thread so it can exit */
DAL_PRINT("Release Read Semaphore");
sem_post(&nfc_read_sem);
DAL_DEBUG("phDal4Nfc_ConfigRelease - doing pthread_join(%d)",
gReadWriteContext.nReadThread);
if (pthread_join(gReadWriteContext.nReadThread, &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
/* Shutdown NFC Chip */
phDal4Nfc_Reset(0);
/* Close the link */
gLinkFunc.close();
if (gDalContext.pDev != NULL) {
nfc_pn544_close(gDalContext.pDev);
}
/* Reset the Read Writer context 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;
static int MsgType= PHDAL4NFC_WRITE_MESSAGE;
int * pmsgType=&MsgType;
phDal4Nfc_Message_t sMsg;
phOsalNfc_Message_t OsalMsg;
if ((NULL != pContext) && (NULL != pHwRef)&&
(NULL != pBuffer) && (0 != length))
{
if( gDalContext.hw_valid== TRUE)
{
if((!gReadWriteContext.nWriteBusy)&&
(!gReadWriteContext.nWaitingOnWrite))
{
DAL_PRINT("phDal4Nfc_Write() : Temporary buffer !! \n");
gReadWriteContext.pTempWriteBuffer = (uint8_t*)malloc(length * sizeof(uint8_t));
/* Make a copy of the passed arguments */
memcpy(gReadWriteContext.pTempWriteBuffer,pBuffer,length);
DAL_DEBUG("phDal4Nfc_Write(): %d\n", length);
gReadWriteContext.pWriteBuffer = gReadWriteContext.pTempWriteBuffer;
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;
/* Send Message and perform physical write in the DefferedCallback */
/* read completed immediately */
sMsg.eMsgType= PHDAL4NFC_WRITE_MESSAGE;
/* Update the state */
phDal4Nfc_FillMsg(&sMsg,&OsalMsg);
phDal4Nfc_DeferredCall((pphDal4Nfc_DeferFuncPointer_t)phDal4Nfc_DeferredCb,(void *)pmsgType);
memset(&sMsg,0,sizeof(phDal4Nfc_Message_t));
memset(&OsalMsg,0,sizeof(phOsalNfc_Message_t));
}
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;
/* Update the return state */
result = NFCSTATUS_PENDING;
/* unlock reader thread */
sem_post(&nfc_read_sem);
}
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;
}
}
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)
{
/* not used */
DAL_PRINT("phDal4Nfc_ReadWait");
return 0;
}
/*-----------------------------------------------------------------------------
FUNCTION: phDal4Nfc_ReadWaitCancel
PURPOSE: Cancel the Read wait function.
-----------------------------------------------------------------------------*/
NFCSTATUS phDal4Nfc_ReadWaitCancel( void *pContext, void *pHwRef)
{
DAL_PRINT("phDal4Nfc_ReadWaitCancel");
/* unlock read semaphore */
sem_post(&nfc_read_sem);
return 0;
}
/*-----------------------------------------------------------------------------
FUNCTION: phDal4Nfc_Config
PURPOSE: Configure the serial port.
-----------------------------------------------------------------------------*/
NFCSTATUS phDal4Nfc_Config(pphDal4Nfc_sConfig_t config,void **phwref)
{
NFCSTATUS retstatus = NFCSTATUS_SUCCESS;
const hw_module_t* hw_module;
nfc_pn544_device_t* pn544_dev;
uint8_t num_eeprom_settings;
uint8_t* eeprom_settings;
int ret;
/* Retrieve the hw module from the Android NFC HAL */
ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module);
if (ret) {
ALOGE("hw_get_module() failed");
return NFCSTATUS_FAILED;
}
ret = nfc_pn544_open(hw_module, &pn544_dev);
if (ret) {
ALOGE("Could not open pn544 hw_module");
return NFCSTATUS_FAILED;
}
config->deviceNode = pn544_dev->device_node;
if (config->deviceNode == NULL) {
ALOGE("deviceNode NULL");
return NFCSTATUS_FAILED;
}
DAL_PRINT("phDal4Nfc_Config");
if ((config == NULL) || (phwref == NULL))
return NFCSTATUS_INVALID_PARAMETER;
/* Register the link callbacks */
memset(&gLinkFunc, 0, sizeof(phDal4Nfc_link_cbk_interface_t));
switch(pn544_dev->linktype)
{
case PN544_LINK_TYPE_UART:
case PN544_LINK_TYPE_USB:
{
DAL_PRINT("UART link Config");
/* 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;
gLinkFunc.reset = phDal4Nfc_uart_reset;
}
break;
case PN544_LINK_TYPE_I2C:
{
DAL_PRINT("I2C link Config");
/* i2c 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;
gLinkFunc.reset = phDal4Nfc_i2c_reset;
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 Reader Thread values to NULL */
memset((void *)&gReadWriteContext,0,sizeof(gReadWriteContext));
gReadWriteContext.nReadThreadAlive = TRUE;
gReadWriteContext.nWriteBusy = FALSE;
gReadWriteContext.nWaitingOnWrite = FALSE;
/* 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
gDalContext.pDev = pn544_dev;
/* Start Read and Write Threads */
if(NFCSTATUS_SUCCESS != phDal4Nfc_StartThreads())
{
return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED);
}
gDalContext.hw_valid = TRUE;
phDal4Nfc_Reset(1);
phDal4Nfc_Reset(0);
phDal4Nfc_Reset(1);
return NFCSTATUS_SUCCESS;
}
/*-----------------------------------------------------------------------------
FUNCTION: phDal4Nfc_Reset
PURPOSE: Reset the PN544, using the VEN pin
-----------------------------------------------------------------------------*/
NFCSTATUS phDal4Nfc_Reset(long level)
{
NFCSTATUS retstatus = NFCSTATUS_SUCCESS;
DAL_DEBUG("phDal4Nfc_Reset: VEN to %ld",level);
retstatus = gLinkFunc.reset(level);
return retstatus;
}
/*-----------------------------------------------------------------------------
FUNCTION: phDal4Nfc_Download
PURPOSE: Put the PN544 in download mode, using the GPIO4 pin
-----------------------------------------------------------------------------*/
NFCSTATUS phDal4Nfc_Download()
{
NFCSTATUS retstatus = NFCSTATUS_SUCCESS;
DAL_DEBUG("phDal4Nfc_Download: GPIO4 to %d",1);
usleep(10000);
retstatus = phDal4Nfc_Reset(2);
return retstatus;
}
/*-----------------------------------------------------------------------------------
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;
int i2c_error_count;
int i2c_workaround;
if (gDalContext.pDev != NULL) {
i2c_workaround = gDalContext.pDev->enable_i2c_workaround;
} else {
ALOGE("gDalContext.pDev is not set");
return NFCSTATUS_FAILED;
}
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*/
DAL_PRINT("RX Thread \n");
DAL_DEBUG("\nRX Thread nReadThreadAlive = %d",gReadWriteContext.nReadThreadAlive);
DAL_DEBUG("\nRX Thread nWaitingOnRead = %d",gReadWriteContext.nWaitingOnRead);
while(gReadWriteContext.nReadThreadAlive) /* Thread Loop */
{
/* Check for the read request from user */
DAL_PRINT("RX Thread Sem Lock\n");
sem_wait(&nfc_read_sem);
DAL_PRINT("RX Thread Sem UnLock\n");
if (!gReadWriteContext.nReadThreadAlive)
{
/* got the signal that we should exit. NOTE: we don't
attempt to read below, since the read may block */
break;
}
/* Issue read operation.*/
i2c_error_count = 0;
retry:
gReadWriteContext.nNbOfBytesRead=0;
DAL_DEBUG("RX Thread *New *** *****Request Length = %d",gReadWriteContext.nNbOfBytesToRead);
memsetRet=memset(gReadWriteContext.pReadBuffer,0,gReadWriteContext.nNbOfBytesToRead);
/* Wait for IRQ !!! */
gReadWriteContext.nNbOfBytesRead = gLinkFunc.read(gReadWriteContext.pReadBuffer, gReadWriteContext.nNbOfBytesToRead);
/* Reading the value 0x57 indicates a HW I2C error at I2C address 0x57
* (pn544). There should not be false positives because a read of length 1
* must be a HCI length read, and a length of 0x57 is impossible (max is 33).
*/
if(i2c_workaround && gReadWriteContext.nNbOfBytesToRead == 1 &&
gReadWriteContext.pReadBuffer[0] == 0x57)
{
i2c_error_count++;
DAL_DEBUG("RX Thread Read 0x57 %d times\n", i2c_error_count);
if (i2c_error_count < 5) {
usleep(2000);
goto retry;
}
DAL_PRINT("RX Thread NOTHING TO READ, RECOVER");
phOsalNfc_RaiseException(phOsalNfc_e_UnrecovFirmwareErr,1);
}
else
{
i2c_error_count = 0;
if (low_level_traces)
{
phOsalNfc_PrintData("RECV", (uint16_t)gReadWriteContext.nNbOfBytesRead,
gReadWriteContext.pReadBuffer, low_level_traces);
}
DAL_DEBUG("RX Thread Read ok. nbToRead=%d\n", gReadWriteContext.nNbOfBytesToRead);
DAL_DEBUG("RX Thread NbReallyRead=%d\n", gReadWriteContext.nNbOfBytesRead);
/* DAL_PRINT("RX Thread ReadBuff[]={ ");
for (i = 0; i < gReadWriteContext.nNbOfBytesRead; i++)
{
DAL_DEBUG("RX Thread 0x%x ", gReadWriteContext.pReadBuffer[i]);
}
DAL_PRINT("RX Thread }\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));
}
} /* End of thread Loop*/
DAL_PRINT("RX Thread exiting");
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 thread.
*
* \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;
if(sem_init(&nfc_read_sem, 0, 0) == -1)
{
DAL_PRINT("NFC Init Semaphore creation Error");
return -1;
}
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));
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;
int i;
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;
if (gReadWriteContext.nNbOfBytesRead == gReadWriteContext.nNbOfBytesToRead) {
TransactionInfo.status=NFCSTATUS_SUCCESS;
} else {
TransactionInfo.status=NFCSTATUS_READ_FAILED;
}
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_WRITE_MESSAGE:
DAL_PRINT(" Dal deferred write called \n");
if(low_level_traces)
{
phOsalNfc_PrintData("SEND", (uint16_t)gReadWriteContext.nNbOfBytesToWrite,
gReadWriteContext.pWriteBuffer, low_level_traces);
}
/* DAL_DEBUG("dalMsg->transactInfo.length : %d\n", dalMsg->transactInfo.length); */
/* Make a Physical WRITE */
/* NOTE: need to usleep(3000) here if the write is for SWP */
usleep(500); /* NXP advise 500us sleep required between I2C writes */
gReadWriteContext.nNbOfBytesWritten = gLinkFunc.write(gReadWriteContext.pWriteBuffer, gReadWriteContext.nNbOfBytesToWrite);
if (gReadWriteContext.nNbOfBytesWritten != gReadWriteContext.nNbOfBytesToWrite)
{
/* controller may be in standby. do it again! */
usleep(10000); /* wait 10 ms */
gReadWriteContext.nNbOfBytesWritten = gLinkFunc.write(gReadWriteContext.pWriteBuffer, gReadWriteContext.nNbOfBytesToWrite);
}
if (gReadWriteContext.nNbOfBytesWritten != gReadWriteContext.nNbOfBytesToWrite)
{
/* Report write failure or timeout */
DAL_PRINT(" Physical Write Error !!! \n");
TransactionInfo.length=(uint16_t)gReadWriteContext.nNbOfBytesWritten;
TransactionInfo.status = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_BOARD_COMMUNICATION_ERROR);
}
else
{
DAL_PRINT(" Physical Write Success \n");
TransactionInfo.length=(uint16_t)gReadWriteContext.nNbOfBytesWritten;
TransactionInfo.status=NFCSTATUS_SUCCESS;
/* DAL_PRINT("WriteBuff[]={ ");
for (i = 0; i < gReadWriteContext.nNbOfBytesWritten; i++)
{
DAL_DEBUG("0x%x ", gReadWriteContext.pWriteBuffer[i]);
}
DAL_PRINT("}\n"); */
// Free TempWriteBuffer
if(gReadWriteContext.pTempWriteBuffer != NULL)
{
free(gReadWriteContext.pTempWriteBuffer);
}
}
/* Reset Write context */
gReadWriteContext.nWriteBusy = FALSE;
gReadWriteContext.nWaitingOnWrite = FALSE;
/* call LLC callback */
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;
#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
}
#undef _DAL_4_NFC_C