blob: a2f51be5ba2225159cd46ad34cf4c6801fd30808 [file] [log] [blame]
/*
* Copyright (C) 2012-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.
*/
#include <phNxpNciHal_NfcDepSWPrio.h>
#include <phNxpLog.h>
#include <phNxpNciHal.h>
#define CUSTOM_POLL_TIMEOUT 160 /* Timeout value to wait for NFC-DEP detection.*/
#define CLEAN_UP_TIMEOUT 250
#define MAX_WRITE_RETRY 5
/******************* Global variables *****************************************/
extern phNxpNciHal_Control_t nxpncihal_ctrl;
extern NFCSTATUS phNxpNciHal_send_ext_cmd(uint16_t cmd_len, uint8_t *p_cmd);
static uint8_t cmd_stop_rf_discovery[] = { 0x21, 0x06, 0x01, 0x00 }; /* IDLE */
static uint8_t cmd_resume_rf_discovery[] = { 0x21, 0x06, 0x01, 0x03 }; /* RF_DISCOVER */
/*RF_DISCOVER_SELECT_CMD*/
static uint8_t cmd_select_rf_discovery[] = {0x21,0x04,0x03,0x01,0x04,0x02 };
static uint8_t cmd_poll[64];
static uint8_t cmd_poll_len = 0;
int discover_type = 0xFF;
uint32_t cleanup_timer;
/*PRIO LOGIC related dead functions undefined*/
#ifdef P2P_PRIO_LOGIC_HAL_IMP
static int iso_dep_detected = 0x00;
static int poll_timer_fired = 0x00;
static uint8_t bIgnorep2plogic = 0;
static uint8_t *p_iso_ntf_buff = NULL; /* buffer to store second notification */
static uint8_t bIgnoreIsoDep = 0;
static uint32_t custom_poll_timer;
/************** NFC-DEP SW PRIO functions ***************************************/
static NFCSTATUS phNxpNciHal_start_polling_loop(void);
static NFCSTATUS phNxpNciHal_stop_polling_loop(void);
static NFCSTATUS phNxpNciHal_resume_polling_loop(void);
static void phNxpNciHal_NfcDep_store_ntf(uint8_t *p_cmd_data, uint16_t cmd_len);
/*******************************************************************************
**
** Function cleanup_timer_handler
**
** Description Callback function for cleanup timer.
**
** Returns None
**
*******************************************************************************/
static void cleanup_timer_handler(uint32_t timerId, void *pContext)
{
NXPLOG_NCIHAL_D(">> cleanup_timer_handler.");
NXPLOG_NCIHAL_D(">> cleanup_timer_handler. ISO_DEP not detected second time.");
phOsalNfc_Timer_Delete(cleanup_timer);
cleanup_timer=0;
iso_dep_detected = 0x00;
EnableP2P_PrioLogic = FALSE;
return;
}
/*******************************************************************************
**
** Function custom_poll_timer_handler
**
** Description Callback function for custom poll timer.
**
** Returns None
**
*******************************************************************************/
static void custom_poll_timer_handler(uint32_t timerId, void *pContext)
{
NXPLOG_NCIHAL_D(">> custom_poll_timer_handler.");
NXPLOG_NCIHAL_D(">> custom_poll_timer_handler. NFC_DEP not detected. so giving early chance to ISO_DEP.");
phOsalNfc_Timer_Delete(custom_poll_timer);
if (iso_dep_detected == 0x01)
{
poll_timer_fired = 0x01;
/*
* Restart polling loop.
* When the polling loop is stopped, polling will be restarted.
*/
NXPLOG_NCIHAL_D(">> custom_poll_timer_handler - restart polling loop.");
phNxpNciHal_stop_polling_loop();
}
else
{
NXPLOG_NCIHAL_E(">> custom_poll_timer_handler - invalid flag state (iso_dep_detected)");
}
return;
}
/*******************************************************************************
**
** Function phNxpNciHal_stop_polling_loop
**
** Description Sends stop polling cmd to NFCC
**
** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
**
*******************************************************************************/
static NFCSTATUS phNxpNciHal_stop_polling_loop()
{
NFCSTATUS status = NFCSTATUS_SUCCESS;
phNxpNciHal_Sem_t cb_data;
pthread_t pthread;
discover_type = STOP_POLLING;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if(pthread_create(&pthread, &attr, tmp_thread, (void*) &discover_type) != 0)
{
NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
}
return status;
}
/*******************************************************************************
**
** Function phNxpNciHal_resume_polling_loop
**
** Description Sends resume polling cmd to NFCC
**
** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
**
*******************************************************************************/
static NFCSTATUS phNxpNciHal_resume_polling_loop()
{
NFCSTATUS status = NFCSTATUS_SUCCESS;
phNxpNciHal_Sem_t cb_data;
pthread_t pthread;
discover_type = RESUME_POLLING;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if(pthread_create(&pthread, &attr, tmp_thread, (void*) &discover_type) != 0)
{
NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
}
return status;
}
/*******************************************************************************
**
** Function phNxpNciHal_start_polling_loop
**
** Description Sends start polling cmd to NFCC
**
** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
**
*******************************************************************************/
NFCSTATUS phNxpNciHal_start_polling_loop()
{
NFCSTATUS status = NFCSTATUS_FAILED;
phNxpNciHal_Sem_t cb_data;
pthread_t pthread;
discover_type = START_POLLING;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if(pthread_create(&pthread, &attr, tmp_thread, (void*) &discover_type) != 0)
{
NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
}
return status;
}
/*******************************************************************************
**
** Function phNxpNciHal_NfcDep_rsp_ext
**
** Description Implements algorithm for NFC-DEP protocol priority over
** ISO-DEP protocol.
** Following the algorithm:
** IF ISO-DEP detected first time,set the ISO-DEP detected flag
** and resume polling loop with 60ms timeout value.
** a) if than NFC-DEP detected than send the response to
** libnfc-nci stack and stop the timer.
** b) if NFC-DEP not detected with in 60ms, than restart the
** polling loop to give early chance to ISO-DEP with a
** cleanup timer.
** c) if ISO-DEP detected second time send the response to
** libnfc-nci stack and stop the cleanup timer.
** d) if ISO-DEP not detected with in cleanup timeout, than
** clear the ISO-DEP detection flag.
**
** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
**
*******************************************************************************/
NFCSTATUS phNxpNciHal_NfcDep_rsp_ext(uint8_t *p_ntf, uint16_t *p_len)
{
NFCSTATUS status = NFCSTATUS_INVALID_PARAMETER;
NXPLOG_NCIHAL_D(">> p_ntf[0]=%02x , p_ntf[1]=%02x",p_ntf[0],p_ntf[1]);
if(p_ntf[0] == 0x41 && p_ntf[1] == 0x04)
{
//Tag selected, Disable P2P Prio logic.
bIgnoreIsoDep = 1;
NXPLOG_NCIHAL_D(">> Tag selected, Disable P2P Prio logic.");
}
else if( ((p_ntf[0] == 0x61 && p_ntf[1] == 0x06) ||
(p_ntf[0] == 0x41 && p_ntf[1] == 0x06) ) && bIgnoreIsoDep == 1
)
{
//Tag deselected, enable P2P Prio logic.
bIgnoreIsoDep = 0x00;
NXPLOG_NCIHAL_D(">> Tag deselected, enable P2P Prio logic.");
}
if (bIgnoreIsoDep == 0x00 &&
p_ntf[0] == 0x61 &&
p_ntf[1] == 0x05 && *p_len > 5)
{
if (p_ntf[5] == 0x04 && p_ntf[6] < 0x80)
{
NXPLOG_NCIHAL_D(">> ISO DEP detected.");
if (iso_dep_detected == 0x00)
{
NXPLOG_NCIHAL_D(
">> ISO DEP detected first time. Resume polling loop");
iso_dep_detected = 0x01;
status = phNxpNciHal_resume_polling_loop();
custom_poll_timer = phOsalNfc_Timer_Create();
NXPLOG_NCIHAL_D("custom poll timer started - %d", custom_poll_timer);
status = phOsalNfc_Timer_Start(custom_poll_timer,
CUSTOM_POLL_TIMEOUT,
&custom_poll_timer_handler,
NULL);
if (NFCSTATUS_SUCCESS == status)
{
NXPLOG_NCIHAL_D("custom poll timer started");
}
else
{
NXPLOG_NCIHAL_E("custom poll timer not started!!!");
status = NFCSTATUS_FAILED;
}
status = NFCSTATUS_FAILED;
}
else
{
NXPLOG_NCIHAL_D(">> ISO DEP detected second time.");
/* Store notification */
phNxpNciHal_NfcDep_store_ntf(p_ntf, *p_len);
/* Stop Cleanup_timer */
phOsalNfc_Timer_Stop(cleanup_timer);
phOsalNfc_Timer_Delete(cleanup_timer);
cleanup_timer=0;
EnableP2P_PrioLogic = FALSE;
iso_dep_detected = 0;
status = NFCSTATUS_SUCCESS;
}
}
else if (p_ntf[5] == 0x05)
{
NXPLOG_NCIHAL_D(">> NFC-DEP Detected - stopping the custom poll timer");
phOsalNfc_Timer_Stop(custom_poll_timer);
phOsalNfc_Timer_Delete(custom_poll_timer);
EnableP2P_PrioLogic = FALSE;
iso_dep_detected = 0;
status = NFCSTATUS_SUCCESS;
}
else
{
NXPLOG_NCIHAL_D(">> detected other technology- stopping the custom poll timer");
phOsalNfc_Timer_Stop(custom_poll_timer);
phOsalNfc_Timer_Delete(custom_poll_timer);
EnableP2P_PrioLogic = FALSE;
iso_dep_detected = 0;
status = NFCSTATUS_INVALID_PARAMETER;
}
}
else if( bIgnoreIsoDep == 0x00 &&
((p_ntf[0] == 0x41 && p_ntf[1] == 0x06) || (p_ntf[0] == 0x61
&& p_ntf[1] == 0x06))
)
{
NXPLOG_NCIHAL_D(">> RF disabled");
if (poll_timer_fired == 0x01)
{
poll_timer_fired = 0x00;
NXPLOG_NCIHAL_D(">>restarting polling loop.");
/* start polling loop */
phNxpNciHal_start_polling_loop();
EnableP2P_PrioLogic = FALSE;
NXPLOG_NCIHAL_D (">> NFC DEP NOT detected - custom poll timer expired - RF disabled");
cleanup_timer = phOsalNfc_Timer_Create();
/* Start cleanup_timer */
NFCSTATUS status = phOsalNfc_Timer_Start(cleanup_timer,
CLEAN_UP_TIMEOUT,
&cleanup_timer_handler,
NULL);
if (NFCSTATUS_SUCCESS == status)
{
NXPLOG_NCIHAL_D("cleanup timer started");
}
else
{
NXPLOG_NCIHAL_E("cleanup timer not started!!!");
status = NFCSTATUS_FAILED;
}
status = NFCSTATUS_FAILED;
}
else
{
status = NFCSTATUS_SUCCESS;
}
}
if (bIgnoreIsoDep == 0x00 &&
iso_dep_detected == 1)
{
if ((p_ntf[0] == 0x41 && p_ntf[1] == 0x06) || (p_ntf[0] == 0x61
&& p_ntf[1] == 0x06))
{
NXPLOG_NCIHAL_D(">>iso_dep_detected Disconnect related notification");
status = NFCSTATUS_FAILED;
}
else
{
NXPLOG_NCIHAL_W("Never come here");
}
}
return status;
}
/*******************************************************************************
**
** Function phNxpNciHal_NfcDep_store_ntf
**
** Description Stores the iso dep notification locally.
**
** Returns None
**
*******************************************************************************/
static void phNxpNciHal_NfcDep_store_ntf(uint8_t *p_cmd_data, uint16_t cmd_len)
{
p_iso_ntf_buff = NULL;
p_iso_ntf_buff = malloc(sizeof (uint8_t) * cmd_len);
if (p_iso_ntf_buff == NULL)
{
NXPLOG_NCIHAL_E("Error allocating memory (p_iso_ntf_buff)");
return;
}
memcpy(p_iso_ntf_buff, p_cmd_data, cmd_len);
bIgnorep2plogic = 1;
}
/*******************************************************************************
**
** Function phNxpNciHal_NfcDep_comapre_ntf
**
** Description Compare the notification with previous iso dep notification.
**
** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
**
*******************************************************************************/
NFCSTATUS phNxpNciHal_NfcDep_comapre_ntf(uint8_t *p_cmd_data, uint16_t cmd_len)
{
NFCSTATUS status = NFCSTATUS_FAILED;
int32_t ret_val = -1;
if (bIgnorep2plogic == 1)
{
ret_val = memcmp(p_cmd_data,p_iso_ntf_buff, cmd_len);
if(ret_val != 0)
{
NXPLOG_NCIHAL_E("Third notification is not equal to last");
}
else
{
NXPLOG_NCIHAL_E("Third notification is equal to last (disable p2p logic)");
status = NFCSTATUS_SUCCESS;
}
bIgnorep2plogic = 0;
}
if (p_iso_ntf_buff != NULL)
{
free(p_iso_ntf_buff);
p_iso_ntf_buff = NULL;
}
return status;
}
extern NFCSTATUS phNxpNciHal_clean_P2P_Prio()
{
NFCSTATUS status = NFCSTATUS_SUCCESS;
iso_dep_detected = 0x00;
EnableP2P_PrioLogic = FALSE;
poll_timer_fired = 0x00;
bIgnorep2plogic = 0x00;
bIgnoreIsoDep = 0x00;
status = phOsalNfc_Timer_Stop(cleanup_timer);
status |= phOsalNfc_Timer_Delete(cleanup_timer);
status |= phOsalNfc_Timer_Stop(custom_poll_timer);
status |= phOsalNfc_Timer_Delete(custom_poll_timer);
cleanup_timer=0;
return status;
}
#endif
/*******************************************************************************
**
** Function hal_write_cb
**
** Description Callback function for hal write.
**
** Returns None
**
*******************************************************************************/
static void hal_write_cb(void *pContext, phTmlNfc_TransactInfo_t *pInfo)
{
phNxpNciHal_Sem_t *p_cb_data = (phNxpNciHal_Sem_t*) pContext;
if (pInfo->wStatus == NFCSTATUS_SUCCESS)
{
NXPLOG_NCIHAL_D("hal_write_cb: write successful status = 0x%x", pInfo->wStatus);
}
else
{
NXPLOG_NCIHAL_E("hal_write_cb: write error status = 0x%x", pInfo->wStatus);
}
p_cb_data->status = pInfo->wStatus;
SEM_POST(p_cb_data);
return;
}
/*******************************************************************************
**
** Function tmp_thread
**
** Description Thread to execute custom poll commands .
**
** Returns None
**
*******************************************************************************/
void *tmp_thread(void *tmp)
{
NFCSTATUS status = NFCSTATUS_SUCCESS;
uint16_t data_len;
NXPLOG_NCIHAL_E("tmp_thread: enter type=0x0%x", *((int*)tmp));
usleep(10*1000);
switch( *((int*)tmp) )
{
case START_POLLING:
{
CONCURRENCY_LOCK();
data_len = phNxpNciHal_write_unlocked(cmd_poll_len, cmd_poll);
CONCURRENCY_UNLOCK();
if(data_len != cmd_poll_len)
{
NXPLOG_NCIHAL_E("phNxpNciHal_start_polling_loop: data len mismatch");
status = NFCSTATUS_FAILED;
}
}
break;
case RESUME_POLLING:
{
CONCURRENCY_LOCK();
data_len = phNxpNciHal_write_unlocked(sizeof(cmd_resume_rf_discovery),
cmd_resume_rf_discovery);
CONCURRENCY_UNLOCK();
if(data_len != sizeof(cmd_resume_rf_discovery))
{
NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
status = NFCSTATUS_FAILED;
}
}
break;
case STOP_POLLING:
{
CONCURRENCY_LOCK();
data_len = phNxpNciHal_write_unlocked(sizeof(cmd_stop_rf_discovery),
cmd_stop_rf_discovery);
CONCURRENCY_UNLOCK();
if(data_len != sizeof(cmd_stop_rf_discovery))
{
NXPLOG_NCIHAL_E("phNxpNciHal_stop_polling_loop: data len mismatch");
status = NFCSTATUS_FAILED;
}
}
break;
case DISCOVER_SELECT:
{
CONCURRENCY_LOCK();
data_len = phNxpNciHal_write_unlocked(sizeof(cmd_select_rf_discovery),
cmd_select_rf_discovery);
CONCURRENCY_UNLOCK();
if(data_len != sizeof(cmd_resume_rf_discovery))
{
NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
status = NFCSTATUS_FAILED;
}
}
break;
default:
NXPLOG_NCIHAL_E("No Matching case");
status = NFCSTATUS_FAILED;
break;
}
NXPLOG_NCIHAL_E("tmp_thread: exit");
return NULL;
}
/*******************************************************************************
**
** Function phNxpNciHal_select_RF_Discovery
**
** Description Sends RF_DISCOVER_SELECT_CMD
** Parameters RfID , RfProtocolType
** Returns NFCSTATUS_PENDING if success
**
*******************************************************************************/
NFCSTATUS phNxpNciHal_select_RF_Discovery(unsigned int RfID,unsigned int RfProtocolType)
{
NFCSTATUS status = NFCSTATUS_SUCCESS;
phNxpNciHal_Sem_t cb_data;
pthread_t pthread;
discover_type = DISCOVER_SELECT;
cmd_select_rf_discovery[3]=RfID;
cmd_select_rf_discovery[4]=RfProtocolType;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if(pthread_create(&pthread, &attr, tmp_thread, (void*) &discover_type) != 0)
{
NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
}
return status;
}
/*******************************************************************************
**
** Function phNxpNciHal_NfcDep_cmd_ext
**
** Description Stores the polling loop configuration locally.
**
** Returns None
**
*******************************************************************************/
void phNxpNciHal_NfcDep_cmd_ext(uint8_t *p_cmd_data, uint16_t *cmd_len)
{
if (p_cmd_data[0] == 0x21 && p_cmd_data[1] == 0x03)
{
if (*cmd_len == 6 && p_cmd_data[3] == 0x01 && p_cmd_data[4] == 0x02
&& p_cmd_data[5] == 0x01)
{
/* DO NOTHING */
}
else
{
/* Store the polling loop configuration */
cmd_poll_len = *cmd_len;
memset(&cmd_poll, 0, cmd_poll_len);
memcpy(&cmd_poll, p_cmd_data, cmd_poll_len);
}
}
return;
}