1/*
2 * Copyright (C) 2012-2014 NXP Semiconductors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <phNxpNciHal_NfcDepSWPrio.h>
18#include <phNxpLog.h>
19#include <phNxpNciHal.h>
20
21#define CUSTOM_POLL_TIMEOUT 160    /* Timeout value to wait for NFC-DEP detection.*/
22#define CLEAN_UP_TIMEOUT 250
23#define MAX_WRITE_RETRY 5
24
25/******************* Global variables *****************************************/
26extern phNxpNciHal_Control_t nxpncihal_ctrl;
27extern NFCSTATUS phNxpNciHal_send_ext_cmd(uint16_t cmd_len, uint8_t *p_cmd);
28static uint8_t cmd_stop_rf_discovery[] = { 0x21, 0x06, 0x01, 0x00 }; /* IDLE */
29static uint8_t cmd_resume_rf_discovery[] = { 0x21, 0x06, 0x01, 0x03 }; /* RF_DISCOVER */
30
31/*RF_DISCOVER_SELECT_CMD*/
32static uint8_t cmd_select_rf_discovery[] = {0x21,0x04,0x03,0x01,0x04,0x02 };
33
34static uint8_t cmd_poll[64];
35static uint8_t cmd_poll_len = 0;
36int discover_type = 0xFF;
37uint32_t cleanup_timer;
38
39/*PRIO LOGIC related dead functions undefined*/
40#ifdef P2P_PRIO_LOGIC_HAL_IMP
41
42static int iso_dep_detected = 0x00;
43static int poll_timer_fired = 0x00;
44static uint8_t bIgnorep2plogic = 0;
45static uint8_t *p_iso_ntf_buff = NULL; /* buffer to store second notification */
46static uint8_t bIgnoreIsoDep = 0;
47static uint32_t custom_poll_timer;
48
49/************** NFC-DEP SW PRIO functions ***************************************/
50
51static NFCSTATUS phNxpNciHal_start_polling_loop(void);
52static NFCSTATUS phNxpNciHal_stop_polling_loop(void);
53static NFCSTATUS phNxpNciHal_resume_polling_loop(void);
54static void phNxpNciHal_NfcDep_store_ntf(uint8_t *p_cmd_data, uint16_t cmd_len);
55
56
57/*******************************************************************************
58**
59** Function         cleanup_timer_handler
60**
61** Description      Callback function for cleanup timer.
62**
63** Returns          None
64**
65*******************************************************************************/
66static void cleanup_timer_handler(uint32_t timerId, void *pContext)
67{
68    NXPLOG_NCIHAL_D(">> cleanup_timer_handler.");
69
70    NXPLOG_NCIHAL_D(">> cleanup_timer_handler. ISO_DEP not detected second time.");
71
72    phOsalNfc_Timer_Delete(cleanup_timer);
73    cleanup_timer=0;
74    iso_dep_detected = 0x00;
75    EnableP2P_PrioLogic = FALSE;
76    return;
77}
78
79/*******************************************************************************
80**
81** Function         custom_poll_timer_handler
82**
83** Description      Callback function for custom poll timer.
84**
85** Returns          None
86**
87*******************************************************************************/
88static void custom_poll_timer_handler(uint32_t timerId, void *pContext)
89{
90    NXPLOG_NCIHAL_D(">> custom_poll_timer_handler.");
91
92    NXPLOG_NCIHAL_D(">> custom_poll_timer_handler. NFC_DEP not detected. so giving early chance to ISO_DEP.");
93
94    phOsalNfc_Timer_Delete(custom_poll_timer);
95
96    if (iso_dep_detected == 0x01)
97    {
98        poll_timer_fired = 0x01;
99
100        /*
101         * Restart polling loop.
102         * When the polling loop is stopped, polling will be restarted.
103         */
104        NXPLOG_NCIHAL_D(">> custom_poll_timer_handler - restart polling loop.");
105
106        phNxpNciHal_stop_polling_loop();
107    }
108    else
109    {
110        NXPLOG_NCIHAL_E(">> custom_poll_timer_handler - invalid flag state (iso_dep_detected)");
111    }
112
113    return;
114}
115/*******************************************************************************
116**
117** Function         phNxpNciHal_stop_polling_loop
118**
119** Description      Sends stop polling cmd to NFCC
120**
121** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
122**
123*******************************************************************************/
124static NFCSTATUS phNxpNciHal_stop_polling_loop()
125{
126    NFCSTATUS status = NFCSTATUS_SUCCESS;
127    phNxpNciHal_Sem_t cb_data;
128    pthread_t pthread;
129    discover_type = STOP_POLLING;
130
131    pthread_attr_t attr;
132    pthread_attr_init(&attr);
133    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
134    if(pthread_create(&pthread, &attr, tmp_thread, (void*) &discover_type) != 0)
135    {
136        NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
137    }
138    return status;
139}
140
141/*******************************************************************************
142**
143** Function         phNxpNciHal_resume_polling_loop
144**
145** Description      Sends resume polling cmd to NFCC
146**
147** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
148**
149*******************************************************************************/
150static NFCSTATUS phNxpNciHal_resume_polling_loop()
151{
152    NFCSTATUS status = NFCSTATUS_SUCCESS;
153    phNxpNciHal_Sem_t cb_data;
154    pthread_t pthread;
155    discover_type = RESUME_POLLING;
156
157    pthread_attr_t attr;
158    pthread_attr_init(&attr);
159    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
160    if(pthread_create(&pthread, &attr, tmp_thread, (void*) &discover_type) != 0)
161    {
162        NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
163    }
164    return status;
165}
166
167/*******************************************************************************
168**
169** Function         phNxpNciHal_start_polling_loop
170**
171** Description      Sends start polling cmd to NFCC
172**
173** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
174**
175*******************************************************************************/
176NFCSTATUS phNxpNciHal_start_polling_loop()
177{
178    NFCSTATUS status = NFCSTATUS_FAILED;
179    phNxpNciHal_Sem_t cb_data;
180    pthread_t pthread;
181    discover_type = START_POLLING;
182
183    pthread_attr_t attr;
184    pthread_attr_init(&attr);
185    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
186    if(pthread_create(&pthread, &attr, tmp_thread, (void*) &discover_type) != 0)
187    {
188        NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
189    }
190    return status;
191}
192
193/*******************************************************************************
194**
195** Function         phNxpNciHal_NfcDep_rsp_ext
196**
197** Description      Implements algorithm for NFC-DEP protocol priority over
198**                  ISO-DEP protocol.
199**                  Following the algorithm:
200**                  IF ISO-DEP detected first time,set the ISO-DEP detected flag
201**                  and resume polling loop with 60ms timeout value.
202**                      a) if than NFC-DEP detected than send the response to
203**                       libnfc-nci stack and stop the timer.
204**                      b) if NFC-DEP not detected with in 60ms, than restart the
205**                          polling loop to give early chance to ISO-DEP with a
206**                          cleanup timer.
207**                      c) if ISO-DEP detected second time send the response to
208**                          libnfc-nci stack and stop the cleanup timer.
209**                      d) if ISO-DEP not detected with in cleanup timeout, than
210**                          clear the ISO-DEP detection flag.
211**
212** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
213**
214*******************************************************************************/
215NFCSTATUS phNxpNciHal_NfcDep_rsp_ext(uint8_t *p_ntf, uint16_t *p_len)
216{
217    NFCSTATUS status = NFCSTATUS_INVALID_PARAMETER;
218
219    NXPLOG_NCIHAL_D(">> p_ntf[0]=%02x , p_ntf[1]=%02x",p_ntf[0],p_ntf[1]);
220
221    if(p_ntf[0] == 0x41 && p_ntf[1] == 0x04)
222    {
223        //Tag selected, Disable P2P Prio logic.
224        bIgnoreIsoDep = 1;
225        NXPLOG_NCIHAL_D(">> Tag selected, Disable P2P Prio logic.");
226
227    }
228    else if( ((p_ntf[0] == 0x61 && p_ntf[1] == 0x06) ||
229            (p_ntf[0] == 0x41 && p_ntf[1] == 0x06) ) && bIgnoreIsoDep == 1
230            )
231    {
232        //Tag deselected, enable P2P Prio logic.
233        bIgnoreIsoDep = 0x00;
234        NXPLOG_NCIHAL_D(">> Tag deselected, enable P2P Prio logic.");
235
236    }
237    if (bIgnoreIsoDep == 0x00 &&
238            p_ntf[0] == 0x61 &&
239            p_ntf[1] == 0x05 && *p_len > 5)
240    {
241        if (p_ntf[5] == 0x04 && p_ntf[6] < 0x80)
242        {
243            NXPLOG_NCIHAL_D(">> ISO DEP detected.");
244
245            if (iso_dep_detected == 0x00)
246            {
247                NXPLOG_NCIHAL_D(
248                        ">> ISO DEP detected first time. Resume polling loop");
249
250                iso_dep_detected = 0x01;
251                status = phNxpNciHal_resume_polling_loop();
252
253                custom_poll_timer = phOsalNfc_Timer_Create();
254                NXPLOG_NCIHAL_D("custom poll timer started - %d", custom_poll_timer);
255
256                status = phOsalNfc_Timer_Start(custom_poll_timer,
257                        CUSTOM_POLL_TIMEOUT,
258                        &custom_poll_timer_handler,
259                        NULL);
260
261                if (NFCSTATUS_SUCCESS == status)
262                {
263                    NXPLOG_NCIHAL_D("custom poll timer started");
264                }
265                else
266                {
267                    NXPLOG_NCIHAL_E("custom poll timer not started!!!");
268                    status  = NFCSTATUS_FAILED;
269                }
270
271                status = NFCSTATUS_FAILED;
272            }
273            else
274            {
275                NXPLOG_NCIHAL_D(">> ISO DEP detected second time.");
276                /* Store notification */
277                phNxpNciHal_NfcDep_store_ntf(p_ntf, *p_len);
278
279                /* Stop Cleanup_timer */
280                phOsalNfc_Timer_Stop(cleanup_timer);
281                phOsalNfc_Timer_Delete(cleanup_timer);
282                cleanup_timer=0;
283                EnableP2P_PrioLogic = FALSE;
284                iso_dep_detected = 0;
285                status = NFCSTATUS_SUCCESS;
286            }
287        }
288        else if (p_ntf[5] == 0x05)
289        {
290            NXPLOG_NCIHAL_D(">> NFC-DEP Detected - stopping the custom poll timer");
291
292            phOsalNfc_Timer_Stop(custom_poll_timer);
293            phOsalNfc_Timer_Delete(custom_poll_timer);
294            EnableP2P_PrioLogic = FALSE;
295            iso_dep_detected = 0;
296            status = NFCSTATUS_SUCCESS;
297        }
298        else
299        {
300            NXPLOG_NCIHAL_D(">>  detected other technology- stopping the custom poll timer");
301            phOsalNfc_Timer_Stop(custom_poll_timer);
302            phOsalNfc_Timer_Delete(custom_poll_timer);
303            EnableP2P_PrioLogic = FALSE;
304            iso_dep_detected = 0;
305            status = NFCSTATUS_INVALID_PARAMETER;
306        }
307    }
308    else if( bIgnoreIsoDep == 0x00 &&
309            ((p_ntf[0] == 0x41 && p_ntf[1] == 0x06) || (p_ntf[0] == 0x61
310            && p_ntf[1] == 0x06))
311            )
312    {
313        NXPLOG_NCIHAL_D(">> RF disabled");
314        if (poll_timer_fired == 0x01)
315        {
316            poll_timer_fired = 0x00;
317
318            NXPLOG_NCIHAL_D(">>restarting polling loop.");
319
320            /* start polling loop */
321            phNxpNciHal_start_polling_loop();
322            EnableP2P_PrioLogic = FALSE;
323            NXPLOG_NCIHAL_D (">> NFC DEP NOT  detected - custom poll timer expired - RF disabled");
324
325            cleanup_timer = phOsalNfc_Timer_Create();
326
327            /* Start cleanup_timer */
328            NFCSTATUS status = phOsalNfc_Timer_Start(cleanup_timer,
329                    CLEAN_UP_TIMEOUT,
330                    &cleanup_timer_handler,
331                    NULL);
332
333            if (NFCSTATUS_SUCCESS == status)
334            {
335                NXPLOG_NCIHAL_D("cleanup timer started");
336            }
337            else
338            {
339                NXPLOG_NCIHAL_E("cleanup timer not started!!!");
340                status  = NFCSTATUS_FAILED;
341            }
342
343            status = NFCSTATUS_FAILED;
344        }
345        else
346        {
347            status = NFCSTATUS_SUCCESS;
348        }
349    }
350    if (bIgnoreIsoDep == 0x00 &&
351            iso_dep_detected == 1)
352    {
353        if ((p_ntf[0] == 0x41 && p_ntf[1] == 0x06) || (p_ntf[0] == 0x61
354                && p_ntf[1] == 0x06))
355        {
356            NXPLOG_NCIHAL_D(">>iso_dep_detected Disconnect related notification");
357            status = NFCSTATUS_FAILED;
358        }
359        else
360        {
361            NXPLOG_NCIHAL_W("Never come here");
362        }
363    }
364
365    return status;
366}
367/*******************************************************************************
368**
369** Function         phNxpNciHal_NfcDep_store_ntf
370**
371** Description      Stores the iso dep notification locally.
372**
373** Returns          None
374**
375*******************************************************************************/
376static void phNxpNciHal_NfcDep_store_ntf(uint8_t *p_cmd_data, uint16_t cmd_len)
377{
378    p_iso_ntf_buff = NULL;
379
380    p_iso_ntf_buff = malloc(sizeof (uint8_t) * cmd_len);
381    if (p_iso_ntf_buff == NULL)
382    {
383        NXPLOG_NCIHAL_E("Error allocating memory (p_iso_ntf_buff)");
384        return;
385    }
386    memcpy(p_iso_ntf_buff, p_cmd_data, cmd_len);
387    bIgnorep2plogic = 1;
388}
389
390/*******************************************************************************
391**
392** Function         phNxpNciHal_NfcDep_comapre_ntf
393**
394** Description      Compare the notification with previous iso dep notification.
395**
396** Returns          NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED
397**
398*******************************************************************************/
399NFCSTATUS phNxpNciHal_NfcDep_comapre_ntf(uint8_t *p_cmd_data, uint16_t cmd_len)
400{
401   NFCSTATUS status = NFCSTATUS_FAILED;
402   int32_t ret_val = -1;
403
404   if (bIgnorep2plogic == 1)
405   {
406        ret_val = memcmp(p_cmd_data,p_iso_ntf_buff, cmd_len);
407        if(ret_val != 0)
408        {
409            NXPLOG_NCIHAL_E("Third notification is not equal to last");
410        }
411        else
412        {
413            NXPLOG_NCIHAL_E("Third notification is equal to last (disable p2p logic)");
414            status = NFCSTATUS_SUCCESS;
415        }
416        bIgnorep2plogic = 0;
417    }
418    if (p_iso_ntf_buff != NULL)
419    {
420        free(p_iso_ntf_buff);
421        p_iso_ntf_buff = NULL;
422    }
423
424    return status;
425}
426
427
428extern NFCSTATUS phNxpNciHal_clean_P2P_Prio()
429{
430    NFCSTATUS status = NFCSTATUS_SUCCESS;
431
432    iso_dep_detected = 0x00;
433    EnableP2P_PrioLogic = FALSE;
434    poll_timer_fired = 0x00;
435    bIgnorep2plogic = 0x00;
436    bIgnoreIsoDep = 0x00;
437
438    status = phOsalNfc_Timer_Stop(cleanup_timer);
439    status |= phOsalNfc_Timer_Delete(cleanup_timer);
440
441    status |= phOsalNfc_Timer_Stop(custom_poll_timer);
442    status |= phOsalNfc_Timer_Delete(custom_poll_timer);
443    cleanup_timer=0;
444    return status;
445}
446
447#endif
448/*******************************************************************************
449**
450** Function         hal_write_cb
451**
452** Description      Callback function for hal write.
453**
454** Returns          None
455**
456*******************************************************************************/
457static void hal_write_cb(void *pContext, phTmlNfc_TransactInfo_t *pInfo)
458{
459    phNxpNciHal_Sem_t *p_cb_data = (phNxpNciHal_Sem_t*) pContext;
460
461    if (pInfo->wStatus == NFCSTATUS_SUCCESS)
462    {
463        NXPLOG_NCIHAL_D("hal_write_cb: write successful status = 0x%x", pInfo->wStatus);
464    }
465    else
466    {
467        NXPLOG_NCIHAL_E("hal_write_cb: write error status = 0x%x", pInfo->wStatus);
468    }
469
470    p_cb_data->status = pInfo->wStatus;
471
472    SEM_POST(p_cb_data);
473    return;
474}
475
476/*******************************************************************************
477 **
478 ** Function         tmp_thread
479 **
480 ** Description      Thread to execute custom poll commands .
481 **
482 ** Returns          None
483 **
484 *******************************************************************************/
485void *tmp_thread(void *tmp)
486{
487    NFCSTATUS status = NFCSTATUS_SUCCESS;
488    uint16_t data_len;
489    NXPLOG_NCIHAL_E("tmp_thread: enter type=0x0%x",  *((int*)tmp));
490    usleep(10*1000);
491
492    switch( *((int*)tmp) )
493    {
494    case START_POLLING:
495    {
496        CONCURRENCY_LOCK();
497        data_len = phNxpNciHal_write_unlocked(cmd_poll_len, cmd_poll);
498        CONCURRENCY_UNLOCK();
499
500        if(data_len != cmd_poll_len)
501        {
502            NXPLOG_NCIHAL_E("phNxpNciHal_start_polling_loop: data len mismatch");
503            status = NFCSTATUS_FAILED;
504        }
505    }
506    break;
507
508    case RESUME_POLLING:
509    {
510        CONCURRENCY_LOCK();
511        data_len = phNxpNciHal_write_unlocked(sizeof(cmd_resume_rf_discovery),
512                cmd_resume_rf_discovery);
513        CONCURRENCY_UNLOCK();
514
515        if(data_len != sizeof(cmd_resume_rf_discovery))
516        {
517            NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
518            status = NFCSTATUS_FAILED;
519        }
520    }
521    break;
522
523    case STOP_POLLING:
524    {
525        CONCURRENCY_LOCK();
526        data_len = phNxpNciHal_write_unlocked(sizeof(cmd_stop_rf_discovery),
527                cmd_stop_rf_discovery);
528        CONCURRENCY_UNLOCK();
529
530        if(data_len != sizeof(cmd_stop_rf_discovery))
531        {
532            NXPLOG_NCIHAL_E("phNxpNciHal_stop_polling_loop: data len mismatch");
533            status = NFCSTATUS_FAILED;
534        }
535    }
536    break;
537
538    case DISCOVER_SELECT:
539    {
540        CONCURRENCY_LOCK();
541        data_len = phNxpNciHal_write_unlocked(sizeof(cmd_select_rf_discovery),
542                cmd_select_rf_discovery);
543        CONCURRENCY_UNLOCK();
544
545        if(data_len != sizeof(cmd_resume_rf_discovery))
546        {
547            NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop: data len mismatch");
548            status = NFCSTATUS_FAILED;
549        }
550    }
551    break;
552
553    default:
554        NXPLOG_NCIHAL_E("No Matching case");
555        status = NFCSTATUS_FAILED;
556        break;
557    }
558
559    NXPLOG_NCIHAL_E("tmp_thread: exit");
560    return NULL;
561}
562/*******************************************************************************
563 **
564 ** Function         phNxpNciHal_select_RF_Discovery
565 **
566 ** Description     Sends RF_DISCOVER_SELECT_CMD
567 ** Parameters    RfID ,  RfProtocolType
568 ** Returns          NFCSTATUS_PENDING if success
569 **
570 *******************************************************************************/
571NFCSTATUS phNxpNciHal_select_RF_Discovery(unsigned int RfID,unsigned int RfProtocolType)
572{
573    NFCSTATUS status = NFCSTATUS_SUCCESS;
574    phNxpNciHal_Sem_t cb_data;
575    pthread_t pthread;
576    discover_type = DISCOVER_SELECT;
577    cmd_select_rf_discovery[3]=RfID;
578    cmd_select_rf_discovery[4]=RfProtocolType;
579
580    pthread_attr_t attr;
581    pthread_attr_init(&attr);
582    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
583    if(pthread_create(&pthread, &attr, tmp_thread, (void*) &discover_type) != 0)
584    {
585        NXPLOG_NCIHAL_E("phNxpNciHal_resume_polling_loop");
586    }
587
588    return status;
589}
590/*******************************************************************************
591**
592** Function         phNxpNciHal_NfcDep_cmd_ext
593**
594** Description      Stores the polling loop configuration locally.
595**
596** Returns          None
597**
598*******************************************************************************/
599void phNxpNciHal_NfcDep_cmd_ext(uint8_t *p_cmd_data, uint16_t *cmd_len)
600{
601    if (p_cmd_data[0] == 0x21 && p_cmd_data[1] == 0x03)
602    {
603        if (*cmd_len == 6 && p_cmd_data[3] == 0x01 && p_cmd_data[4] == 0x02
604                && p_cmd_data[5] == 0x01)
605        {
606            /* DO NOTHING */
607        }
608        else
609        {
610            /* Store the polling loop configuration */
611            cmd_poll_len = *cmd_len;
612            memset(&cmd_poll, 0, cmd_poll_len);
613            memcpy(&cmd_poll, p_cmd_data, cmd_poll_len);
614        }
615    }
616
617    return;
618}
619