You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
550 lines
18 KiB
550 lines
18 KiB
/* |
|
* 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 <phNxpLog.h> |
|
#include <phNxpNciHal.h> |
|
#include <phNxpNciHal_NfcDepSWPrio.h> |
|
|
|
/* Timeout value to wait for NFC-DEP detection.*/ |
|
#define CUSTOM_POLL_TIMEOUT 160 |
|
#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("fail to create pthread"); |
|
} |
|
pthread_attr_destroy(&attr); |
|
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("fail to create pthread"); |
|
} |
|
pthread_attr_destroy(&attr); |
|
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("fail to create pthread"); |
|
} |
|
pthread_attr_destroy(&attr); |
|
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("fail to create pthread"); |
|
} |
|
pthread_attr_destroy(&attr); |
|
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; |
|
}
|
|
|