rw_t4t.c revision e9629bad30a9f478b336ab46b8e6e02f7f87af46
1/******************************************************************************
2 *
3 *  Copyright (C) 2010-2014 Broadcom Corporation
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19
20/******************************************************************************
21 *
22 *  This file contains the implementation for Type 4 tag in Reader/Writer
23 *  mode.
24 *
25 ******************************************************************************/
26#include <string.h>
27#include "nfc_target.h"
28#include "bt_types.h"
29#include "trace_api.h"
30
31#if (NFC_INCLUDED == TRUE)
32
33#include "nfc_api.h"
34#include "nfc_int.h"
35#include "rw_api.h"
36#include "rw_int.h"
37#include "tags_int.h"
38#include "gki.h"
39
40/* main state */
41#define RW_T4T_STATE_NOT_ACTIVATED              0x00    /* T4T is not activated                 */
42#define RW_T4T_STATE_IDLE                       0x01    /* waiting for upper layer API          */
43#define RW_T4T_STATE_DETECT_NDEF                0x02    /* performing NDEF detection precedure  */
44#define RW_T4T_STATE_READ_NDEF                  0x03    /* performing read NDEF procedure       */
45#define RW_T4T_STATE_UPDATE_NDEF                0x04    /* performing update NDEF procedure     */
46#define RW_T4T_STATE_PRESENCE_CHECK             0x05    /* checking presence of tag             */
47#define RW_T4T_STATE_SET_READ_ONLY              0x06    /* convert tag to read only             */
48
49/* sub state */
50#define RW_T4T_SUBSTATE_WAIT_SELECT_APP         0x00    /* waiting for response of selecting AID    */
51#define RW_T4T_SUBSTATE_WAIT_SELECT_CC          0x01    /* waiting for response of selecting CC     */
52#define RW_T4T_SUBSTATE_WAIT_CC_FILE            0x02    /* waiting for response of reading CC       */
53#define RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE   0x03    /* waiting for response of selecting NDEF   */
54#define RW_T4T_SUBSTATE_WAIT_READ_NLEN          0x04    /* waiting for response of reading NLEN     */
55#define RW_T4T_SUBSTATE_WAIT_READ_RESP          0x05    /* waiting for response of reading file     */
56#define RW_T4T_SUBSTATE_WAIT_UPDATE_RESP        0x06    /* waiting for response of updating file    */
57#define RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN        0x07    /* waiting for response of updating NLEN    */
58#define RW_T4T_SUBSTATE_WAIT_UPDATE_CC          0x08    /* waiting for response of updating CC      */
59
60#if (BT_TRACE_VERBOSE == TRUE)
61static char *rw_t4t_get_state_name (UINT8 state);
62static char *rw_t4t_get_sub_state_name (UINT8 sub_state);
63#endif
64
65static BOOLEAN rw_t4t_send_to_lower (BT_HDR *p_c_apdu);
66static BOOLEAN rw_t4t_select_file (UINT16 file_id);
67static BOOLEAN rw_t4t_read_file (UINT16 offset, UINT16 length, BOOLEAN is_continue);
68static BOOLEAN rw_t4t_update_nlen (UINT16 ndef_len);
69static BOOLEAN rw_t4t_update_file (void);
70static BOOLEAN rw_t4t_update_cc_to_readonly (void);
71static BOOLEAN rw_t4t_select_application (UINT8 version);
72static BOOLEAN rw_t4t_validate_cc_file (void);
73static void rw_t4t_handle_error (tNFC_STATUS status, UINT8 sw1, UINT8 sw2);
74static void rw_t4t_sm_detect_ndef (BT_HDR *p_r_apdu);
75static void rw_t4t_sm_read_ndef (BT_HDR *p_r_apdu);
76static void rw_t4t_sm_update_ndef (BT_HDR  *p_r_apdu);
77static void rw_t4t_sm_set_readonly (BT_HDR  *p_r_apdu);
78static void rw_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_data);
79
80/*******************************************************************************
81**
82** Function         rw_t4t_send_to_lower
83**
84** Description      Send C-APDU to lower layer
85**
86** Returns          TRUE if success
87**
88*******************************************************************************/
89static BOOLEAN rw_t4t_send_to_lower (BT_HDR *p_c_apdu)
90{
91#if (BT_TRACE_PROTOCOL == TRUE)
92    DispRWT4Tags (p_c_apdu, FALSE);
93#endif
94
95    if (NFC_SendData (NFC_RF_CONN_ID, p_c_apdu) != NFC_STATUS_OK)
96    {
97        RW_TRACE_ERROR0 ("rw_t4t_send_to_lower (): NFC_SendData () failed");
98        return FALSE;
99    }
100
101    nfc_start_quick_timer (&rw_cb.tcb.t4t.timer, NFC_TTYPE_RW_T4T_RESPONSE,
102                           (RW_T4T_TOUT_RESP * QUICK_TIMER_TICKS_PER_SEC) / 1000);
103
104    return TRUE;
105}
106
107/*******************************************************************************
108**
109** Function         rw_t4t_select_file
110**
111** Description      Send Select Command (by File ID) to peer
112**
113** Returns          TRUE if success
114**
115*******************************************************************************/
116static BOOLEAN rw_t4t_select_file (UINT16 file_id)
117{
118    BT_HDR      *p_c_apdu;
119    UINT8       *p;
120
121    RW_TRACE_DEBUG1 ("rw_t4t_select_file (): File ID:0x%04X", file_id);
122
123    p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
124
125    if (!p_c_apdu)
126    {
127        RW_TRACE_ERROR0 ("rw_t4t_select_file (): Cannot allocate buffer");
128        return FALSE;
129    }
130
131    p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
132    p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
133
134    UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
135    UINT8_TO_BE_STREAM (p, T4T_CMD_INS_SELECT);
136    UINT8_TO_BE_STREAM (p, T4T_CMD_P1_SELECT_BY_FILE_ID);
137
138    /* if current version mapping is V2.0 */
139    if (rw_cb.tcb.t4t.version == T4T_VERSION_2_0)
140    {
141        UINT8_TO_BE_STREAM (p, T4T_CMD_P2_FIRST_OR_ONLY_0CH);
142    }
143    else /* version 1.0 */
144    {
145        UINT8_TO_BE_STREAM (p, T4T_CMD_P2_FIRST_OR_ONLY_00H);
146    }
147
148    UINT8_TO_BE_STREAM (p, T4T_FILE_ID_SIZE);
149    UINT16_TO_BE_STREAM (p, file_id);
150
151    p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_FILE_ID_SIZE;
152
153    if (!rw_t4t_send_to_lower (p_c_apdu))
154    {
155        return FALSE;
156    }
157
158    return TRUE;
159}
160
161/*******************************************************************************
162**
163** Function         rw_t4t_read_file
164**
165** Description      Send ReadBinary Command to peer
166**
167** Returns          TRUE if success
168**
169*******************************************************************************/
170static BOOLEAN rw_t4t_read_file (UINT16 offset, UINT16 length, BOOLEAN is_continue)
171{
172    tRW_T4T_CB      *p_t4t = &rw_cb.tcb.t4t;
173    BT_HDR          *p_c_apdu;
174    UINT8           *p;
175
176    RW_TRACE_DEBUG3 ("rw_t4t_read_file () offset:%d, length:%d, is_continue:%d, ",
177                      offset, length, is_continue);
178
179    p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
180
181    if (!p_c_apdu)
182    {
183        RW_TRACE_ERROR0 ("rw_t4t_read_file (): Cannot allocate buffer");
184        return FALSE;
185    }
186
187    /* if this is the first reading */
188    if (is_continue == FALSE)
189    {
190        /* initialise starting offset and total length */
191        /* these will be updated when receiving response */
192        p_t4t->rw_offset = offset;
193        p_t4t->rw_length = length;
194    }
195
196    /* adjust reading length if payload is bigger than max size per single command */
197    if (length > p_t4t->max_read_size)
198    {
199        length = (UINT8) (p_t4t->max_read_size);
200    }
201
202    p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
203    p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
204
205    UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
206    UINT8_TO_BE_STREAM (p, T4T_CMD_INS_READ_BINARY);
207    UINT16_TO_BE_STREAM (p, offset);
208    UINT8_TO_BE_STREAM (p, length); /* Le */
209
210    p_c_apdu->len = T4T_CMD_MIN_HDR_SIZE + 1; /* adding Le */
211
212    if (!rw_t4t_send_to_lower (p_c_apdu))
213    {
214        return FALSE;
215    }
216
217    return TRUE;
218}
219
220/*******************************************************************************
221**
222** Function         rw_t4t_update_nlen
223**
224** Description      Send UpdateBinary Command to update NLEN to peer
225**
226** Returns          TRUE if success
227**
228*******************************************************************************/
229static BOOLEAN rw_t4t_update_nlen (UINT16 ndef_len)
230{
231    BT_HDR          *p_c_apdu;
232    UINT8           *p;
233
234    RW_TRACE_DEBUG1 ("rw_t4t_update_nlen () NLEN:%d", ndef_len);
235
236    p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
237
238    if (!p_c_apdu)
239    {
240        RW_TRACE_ERROR0 ("rw_t4t_update_nlen (): Cannot allocate buffer");
241        return FALSE;
242    }
243
244    p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
245    p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
246
247    UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
248    UINT8_TO_BE_STREAM (p, T4T_CMD_INS_UPDATE_BINARY);
249    UINT16_TO_BE_STREAM (p, 0x0000);                    /* offset for NLEN */
250    UINT8_TO_BE_STREAM (p, T4T_FILE_LENGTH_SIZE);
251    UINT16_TO_BE_STREAM (p, ndef_len);
252
253    p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_FILE_LENGTH_SIZE;
254
255    if (!rw_t4t_send_to_lower (p_c_apdu))
256    {
257        return FALSE;
258    }
259
260    return TRUE;
261}
262
263/*******************************************************************************
264**
265** Function         rw_t4t_update_file
266**
267** Description      Send UpdateBinary Command to peer
268**
269** Returns          TRUE if success
270**
271*******************************************************************************/
272static BOOLEAN rw_t4t_update_file (void)
273{
274    tRW_T4T_CB      *p_t4t = &rw_cb.tcb.t4t;
275    BT_HDR          *p_c_apdu;
276    UINT8           *p;
277    UINT16          length;
278
279    RW_TRACE_DEBUG2 ("rw_t4t_update_file () rw_offset:%d, rw_length:%d",
280                      p_t4t->rw_offset, p_t4t->rw_length);
281
282    p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
283
284    if (!p_c_apdu)
285    {
286        RW_TRACE_ERROR0 ("rw_t4t_write_file (): Cannot allocate buffer");
287        return FALSE;
288    }
289
290    /* try to send all of remaining data */
291    length = p_t4t->rw_length;
292
293    /* adjust updating length if payload is bigger than max size per single command */
294    if (length > p_t4t->max_update_size)
295    {
296        length = (UINT8) (p_t4t->max_update_size);
297    }
298
299    p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
300    p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
301
302    UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
303    UINT8_TO_BE_STREAM (p, T4T_CMD_INS_UPDATE_BINARY);
304    UINT16_TO_BE_STREAM (p, p_t4t->rw_offset);
305    UINT8_TO_BE_STREAM (p, length);
306
307    memcpy (p, p_t4t->p_update_data, length);
308
309    p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + length;
310
311    if (!rw_t4t_send_to_lower (p_c_apdu))
312    {
313        return FALSE;
314    }
315
316    /* adjust offset, length and pointer for remaining data */
317    p_t4t->rw_offset     += length;
318    p_t4t->rw_length     -= length;
319    p_t4t->p_update_data += length;
320
321    return TRUE;
322}
323
324/*******************************************************************************
325**
326** Function         rw_t4t_update_cc_to_readonly
327**
328** Description      Send UpdateBinary Command for changing Write access
329**
330** Returns          TRUE if success
331**
332*******************************************************************************/
333static BOOLEAN rw_t4t_update_cc_to_readonly (void)
334{
335    BT_HDR          *p_c_apdu;
336    UINT8           *p;
337
338    RW_TRACE_DEBUG0 ("rw_t4t_update_cc_to_readonly (): Remove Write access from CC");
339
340    p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
341
342    if (!p_c_apdu)
343    {
344        RW_TRACE_ERROR0 ("rw_t4t_update_cc_to_readonly (): Cannot allocate buffer");
345        return FALSE;
346    }
347
348    p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
349    p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
350
351    /* Add Command Header */
352    UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
353    UINT8_TO_BE_STREAM (p, T4T_CMD_INS_UPDATE_BINARY);
354    UINT16_TO_BE_STREAM (p, (T4T_FC_TLV_OFFSET_IN_CC + T4T_FC_WRITE_ACCESS_OFFSET_IN_TLV)); /* Offset for Read Write access byte of CC */
355    UINT8_TO_BE_STREAM (p, 1); /* Length of write access field in cc interms of bytes */
356
357    /* Remove Write access */
358    UINT8_TO_BE_STREAM (p, T4T_FC_NO_WRITE_ACCESS);
359
360
361    p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + 1;
362
363    if (!rw_t4t_send_to_lower (p_c_apdu))
364    {
365        return FALSE;
366    }
367
368    return TRUE;
369}
370
371/*******************************************************************************
372**
373** Function         rw_t4t_select_application
374**
375** Description      Select Application
376**
377**                  NDEF Tag Application Select - C-APDU
378**
379**                        CLA INS P1 P2 Lc Data(AID)      Le
380**                  V1.0: 00  A4  04 00 07 D2760000850100 -
381**                  V2.0: 00  A4  04 00 07 D2760000850101 00
382**
383** Returns          TRUE if success
384**
385*******************************************************************************/
386static BOOLEAN rw_t4t_select_application (UINT8 version)
387{
388    BT_HDR      *p_c_apdu;
389    UINT8       *p;
390
391    RW_TRACE_DEBUG1 ("rw_t4t_select_application () version:0x%X", version);
392
393    p_c_apdu = (BT_HDR *) GKI_getpoolbuf (NFC_RW_POOL_ID);
394
395    if (!p_c_apdu)
396    {
397        RW_TRACE_ERROR0 ("rw_t4t_select_application (): Cannot allocate buffer");
398        return FALSE;
399    }
400
401    p_c_apdu->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
402    p = (UINT8 *) (p_c_apdu + 1) + p_c_apdu->offset;
403
404    UINT8_TO_BE_STREAM (p, T4T_CMD_CLASS);
405    UINT8_TO_BE_STREAM (p, T4T_CMD_INS_SELECT);
406    UINT8_TO_BE_STREAM (p, T4T_CMD_P1_SELECT_BY_NAME);
407    UINT8_TO_BE_STREAM (p, T4T_CMD_P2_FIRST_OR_ONLY_00H);
408
409    if (version == T4T_VERSION_1_0)   /* this is for V1.0 */
410    {
411        UINT8_TO_BE_STREAM (p, T4T_V10_NDEF_TAG_AID_LEN);
412
413        memcpy (p, t4t_v10_ndef_tag_aid, T4T_V10_NDEF_TAG_AID_LEN);
414
415        p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_V10_NDEF_TAG_AID_LEN;
416    }
417    else if (version == T4T_VERSION_2_0)   /* this is for V2.0 */
418    {
419        UINT8_TO_BE_STREAM (p, T4T_V20_NDEF_TAG_AID_LEN);
420
421        memcpy (p, t4t_v20_ndef_tag_aid, T4T_V20_NDEF_TAG_AID_LEN);
422        p += T4T_V20_NDEF_TAG_AID_LEN;
423
424        UINT8_TO_BE_STREAM (p, 0x00); /* Le set to 0x00 */
425
426        p_c_apdu->len = T4T_CMD_MAX_HDR_SIZE + T4T_V20_NDEF_TAG_AID_LEN + 1;
427    }
428    else
429    {
430        return FALSE;
431    }
432
433    if (!rw_t4t_send_to_lower (p_c_apdu))
434    {
435        return FALSE;
436    }
437
438    return TRUE;
439}
440
441/*******************************************************************************
442**
443** Function         rw_t4t_validate_cc_file
444**
445** Description      Validate CC file and mandatory NDEF TLV
446**
447** Returns          TRUE if success
448**
449*******************************************************************************/
450static BOOLEAN rw_t4t_validate_cc_file (void)
451{
452    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
453
454    RW_TRACE_DEBUG0 ("rw_t4t_validate_cc_file ()");
455
456    if (p_t4t->cc_file.cclen < T4T_CC_FILE_MIN_LEN)
457    {
458        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): CCLEN (%d) is too short",
459                         p_t4t->cc_file.cclen);
460        return FALSE;
461    }
462
463    if (T4T_GET_MAJOR_VERSION (p_t4t->cc_file.version) != T4T_GET_MAJOR_VERSION (p_t4t->version))
464    {
465        RW_TRACE_ERROR2 ("rw_t4t_validate_cc_file (): Peer version (0x%02X) is matched to ours (0x%02X)",
466                         p_t4t->cc_file.version, p_t4t->version);
467        return FALSE;
468    }
469
470    if (p_t4t->cc_file.max_le < 0x000F)
471    {
472        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): MaxLe (%d) is too small",
473                         p_t4t->cc_file.max_le);
474        return FALSE;
475    }
476
477    if (p_t4t->cc_file.max_lc < 0x0001)
478    {
479        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): MaxLc (%d) is too small",
480                         p_t4t->cc_file.max_lc);
481        return FALSE;
482    }
483
484    if (  (p_t4t->cc_file.ndef_fc.file_id == T4T_CC_FILE_ID)
485        ||(p_t4t->cc_file.ndef_fc.file_id == 0xE102)
486        ||(p_t4t->cc_file.ndef_fc.file_id == 0xE103)
487        ||((p_t4t->cc_file.ndef_fc.file_id == 0x0000) && (p_t4t->cc_file.version == 0x20))
488        ||(p_t4t->cc_file.ndef_fc.file_id == 0x3F00)
489        ||(p_t4t->cc_file.ndef_fc.file_id == 0x3FFF)
490        ||(p_t4t->cc_file.ndef_fc.file_id == 0xFFFF)  )
491    {
492        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): File ID (0x%04X) is invalid",
493                          p_t4t->cc_file.ndef_fc.file_id);
494        return FALSE;
495    }
496
497    if (  (p_t4t->cc_file.ndef_fc.max_file_size < 0x0005)
498        ||(p_t4t->cc_file.ndef_fc.max_file_size == 0xFFFF)  )
499    {
500        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): max_file_size (%d) is reserved",
501                         p_t4t->cc_file.ndef_fc.max_file_size);
502        return FALSE;
503    }
504
505    if (p_t4t->cc_file.ndef_fc.read_access != T4T_FC_READ_ACCESS)
506    {
507        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): Read Access (0x%02X) is invalid",
508                          p_t4t->cc_file.ndef_fc.read_access);
509        return FALSE;
510    }
511
512    if (  (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
513        &&(p_t4t->cc_file.ndef_fc.write_access != T4T_FC_NO_WRITE_ACCESS)  )
514    {
515        RW_TRACE_ERROR1 ("rw_t4t_validate_cc_file (): Write Access (0x%02X) is invalid",
516                          p_t4t->cc_file.ndef_fc.write_access);
517        return FALSE;
518    }
519
520    return TRUE;
521}
522
523/*******************************************************************************
524**
525** Function         rw_t4t_handle_error
526**
527** Description      notify error to application and clean up
528**
529** Returns          none
530**
531*******************************************************************************/
532static void rw_t4t_handle_error (tNFC_STATUS status, UINT8 sw1, UINT8 sw2)
533{
534    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
535    tRW_DATA    rw_data;
536    tRW_EVENT   event;
537
538    RW_TRACE_DEBUG4 ("rw_t4t_handle_error (): status:0x%02X, sw1:0x%02X, sw2:0x%02X, state:0x%X",
539                      status, sw1, sw2, p_t4t->state);
540
541    nfc_stop_quick_timer (&p_t4t->timer);
542
543    if (rw_cb.p_cback)
544    {
545        rw_data.status = status;
546
547        rw_data.t4t_sw.sw1    = sw1;
548        rw_data.t4t_sw.sw2    = sw2;
549
550        switch (p_t4t->state)
551        {
552        case RW_T4T_STATE_DETECT_NDEF:
553            rw_data.ndef.flags  = RW_NDEF_FL_UNKNOWN;
554            event = RW_T4T_NDEF_DETECT_EVT;
555            break;
556
557        case RW_T4T_STATE_READ_NDEF:
558            event = RW_T4T_NDEF_READ_FAIL_EVT;
559            break;
560
561        case RW_T4T_STATE_UPDATE_NDEF:
562            event = RW_T4T_NDEF_UPDATE_FAIL_EVT;
563            break;
564
565        case RW_T4T_STATE_PRESENCE_CHECK:
566            event = RW_T4T_PRESENCE_CHECK_EVT;
567            rw_data.status = NFC_STATUS_FAILED;
568            break;
569
570        case RW_T4T_STATE_SET_READ_ONLY:
571            event = RW_T4T_SET_TO_RO_EVT;
572            break;
573
574        default:
575            event = RW_T4T_MAX_EVT;
576            break;
577        }
578
579        p_t4t->state = RW_T4T_STATE_IDLE;
580
581        if (event != RW_T4T_MAX_EVT)
582        {
583            (*(rw_cb.p_cback)) (event, &rw_data);
584        }
585    }
586    else
587    {
588        p_t4t->state = RW_T4T_STATE_IDLE;
589    }
590}
591
592/*******************************************************************************
593**
594** Function         rw_t4t_sm_detect_ndef
595**
596** Description      State machine for NDEF detection procedure
597**
598** Returns          none
599**
600*******************************************************************************/
601static void rw_t4t_sm_detect_ndef (BT_HDR *p_r_apdu)
602{
603    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
604    UINT8       *p, type, length;
605    UINT16      status_words, nlen;
606    tRW_DATA    rw_data;
607
608#if (BT_TRACE_VERBOSE == TRUE)
609    RW_TRACE_DEBUG2 ("rw_t4t_sm_detect_ndef (): sub_state:%s (%d)",
610                      rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
611#else
612    RW_TRACE_DEBUG1 ("rw_t4t_sm_detect_ndef (): sub_state=%d", p_t4t->sub_state);
613#endif
614
615    /* get status words */
616    p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
617    p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
618    BE_STREAM_TO_UINT16 (status_words, p);
619
620    if (status_words != T4T_RSP_CMD_CMPLTED)
621    {
622        /* try V1.0 after failing of V2.0 */
623        if (  (p_t4t->sub_state == RW_T4T_SUBSTATE_WAIT_SELECT_APP)
624            &&(p_t4t->version   == T4T_VERSION_2_0)  )
625        {
626            p_t4t->version = T4T_VERSION_1_0;
627
628            RW_TRACE_DEBUG1 ("rw_t4t_sm_detect_ndef (): retry with version=0x%02X",
629                              p_t4t->version);
630
631            if (!rw_t4t_select_application (T4T_VERSION_1_0))
632            {
633                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
634            }
635            return;
636        }
637
638        p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
639        rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
640        return;
641    }
642
643    switch (p_t4t->sub_state)
644    {
645    case RW_T4T_SUBSTATE_WAIT_SELECT_APP:
646
647        /* NDEF Tag application has been selected then select CC file */
648        if (!rw_t4t_select_file (T4T_CC_FILE_ID))
649        {
650            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
651        }
652        else
653        {
654            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_CC;
655        }
656        break;
657
658    case RW_T4T_SUBSTATE_WAIT_SELECT_CC:
659
660        /* CC file has been selected then read mandatory part of CC file */
661        if (!rw_t4t_read_file (0x00, T4T_CC_FILE_MIN_LEN, FALSE))
662        {
663            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
664        }
665        else
666        {
667            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_CC_FILE;
668        }
669        break;
670
671    case RW_T4T_SUBSTATE_WAIT_CC_FILE:
672
673        /* CC file has been read then validate and select mandatory NDEF file */
674        if (p_r_apdu->len >= T4T_CC_FILE_MIN_LEN + T4T_RSP_STATUS_WORDS_SIZE)
675        {
676            p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
677
678            BE_STREAM_TO_UINT16 (p_t4t->cc_file.cclen, p);
679            BE_STREAM_TO_UINT8 (p_t4t->cc_file.version, p);
680            BE_STREAM_TO_UINT16 (p_t4t->cc_file.max_le, p);
681            BE_STREAM_TO_UINT16 (p_t4t->cc_file.max_lc, p);
682
683            BE_STREAM_TO_UINT8 (type, p);
684            BE_STREAM_TO_UINT8 (length, p);
685
686            if (  (type == T4T_NDEF_FILE_CONTROL_TYPE)
687                &&(length == T4T_FILE_CONTROL_LENGTH)  )
688            {
689                BE_STREAM_TO_UINT16 (p_t4t->cc_file.ndef_fc.file_id, p);
690                BE_STREAM_TO_UINT16 (p_t4t->cc_file.ndef_fc.max_file_size, p);
691                BE_STREAM_TO_UINT8 (p_t4t->cc_file.ndef_fc.read_access, p);
692                BE_STREAM_TO_UINT8 (p_t4t->cc_file.ndef_fc.write_access, p);
693
694#if (BT_TRACE_VERBOSE == TRUE)
695                RW_TRACE_DEBUG0 ("Capability Container (CC) file");
696                RW_TRACE_DEBUG1 ("  CCLEN:  0x%04X",    p_t4t->cc_file.cclen);
697                RW_TRACE_DEBUG1 ("  Version:0x%02X",    p_t4t->cc_file.version);
698                RW_TRACE_DEBUG1 ("  MaxLe:  0x%04X",    p_t4t->cc_file.max_le);
699                RW_TRACE_DEBUG1 ("  MaxLc:  0x%04X",    p_t4t->cc_file.max_lc);
700                RW_TRACE_DEBUG0 ("  NDEF File Control TLV");
701                RW_TRACE_DEBUG1 ("    FileID:      0x%04X", p_t4t->cc_file.ndef_fc.file_id);
702                RW_TRACE_DEBUG1 ("    MaxFileSize: 0x%04X", p_t4t->cc_file.ndef_fc.max_file_size);
703                RW_TRACE_DEBUG1 ("    ReadAccess:  0x%02X", p_t4t->cc_file.ndef_fc.read_access);
704                RW_TRACE_DEBUG1 ("    WriteAccess: 0x%02X", p_t4t->cc_file.ndef_fc.write_access);
705#endif
706
707                if (rw_t4t_validate_cc_file ())
708                {
709                    if (!rw_t4t_select_file (p_t4t->cc_file.ndef_fc.file_id))
710                    {
711                        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
712                    }
713                    else
714                    {
715                        p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE;
716                    }
717                    break;
718                }
719            }
720        }
721
722        /* invalid response or CC file */
723        p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
724        rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
725        break;
726
727    case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE:
728
729        /* NDEF file has been selected then read the first 2 bytes (NLEN) */
730        if (!rw_t4t_read_file (0, T4T_FILE_LENGTH_SIZE, FALSE))
731        {
732            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
733        }
734        else
735        {
736            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_READ_NLEN;
737        }
738        break;
739
740    case RW_T4T_SUBSTATE_WAIT_READ_NLEN:
741
742        /* NLEN has been read then report upper layer */
743        if (p_r_apdu->len == T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE)
744        {
745            /* get length of NDEF */
746            p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
747            BE_STREAM_TO_UINT16 (nlen, p);
748
749            if (nlen <= p_t4t->cc_file.ndef_fc.max_file_size - T4T_FILE_LENGTH_SIZE)
750            {
751                p_t4t->ndef_status = RW_T4T_NDEF_STATUS_NDEF_DETECTED;
752
753                if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
754                {
755                    p_t4t->ndef_status |= RW_T4T_NDEF_STATUS_NDEF_READ_ONLY;
756                }
757
758                /* Get max bytes to read per command */
759                if (p_t4t->cc_file.max_le >= RW_T4T_MAX_DATA_PER_READ)
760                {
761                    p_t4t->max_read_size = RW_T4T_MAX_DATA_PER_READ;
762                }
763                else
764                {
765                    p_t4t->max_read_size = p_t4t->cc_file.max_le;
766                }
767
768                /* Le: valid range is 0x01 to 0xFF */
769                if (p_t4t->max_read_size >= T4T_MAX_LENGTH_LE)
770                {
771                    p_t4t->max_read_size = T4T_MAX_LENGTH_LE;
772                }
773
774                /* Get max bytes to update per command */
775                if (p_t4t->cc_file.max_lc >= RW_T4T_MAX_DATA_PER_WRITE)
776                {
777                    p_t4t->max_update_size = RW_T4T_MAX_DATA_PER_WRITE;
778                }
779                else
780                {
781                    p_t4t->max_update_size = p_t4t->cc_file.max_lc;
782                }
783
784                /* Lc: valid range is 0x01 to 0xFF */
785                if (p_t4t->max_update_size >= T4T_MAX_LENGTH_LC)
786                {
787                    p_t4t->max_update_size = T4T_MAX_LENGTH_LC;
788                }
789
790                p_t4t->ndef_length = nlen;
791                p_t4t->state       = RW_T4T_STATE_IDLE;
792
793                if (rw_cb.p_cback)
794                {
795                    rw_data.ndef.status   = NFC_STATUS_OK;
796                    rw_data.ndef.protocol = NFC_PROTOCOL_ISO_DEP;
797                    rw_data.ndef.max_size = (UINT32) (p_t4t->cc_file.ndef_fc.max_file_size - (UINT16) T4T_FILE_LENGTH_SIZE);
798                    rw_data.ndef.cur_size = nlen;
799                    rw_data.ndef.flags    = RW_NDEF_FL_SUPPORTED | RW_NDEF_FL_FORMATED;
800                    if (p_t4t->cc_file.ndef_fc.write_access != T4T_FC_WRITE_ACCESS)
801                    {
802                        rw_data.ndef.flags    |= RW_NDEF_FL_READ_ONLY;
803                    }
804
805                    (*(rw_cb.p_cback)) (RW_T4T_NDEF_DETECT_EVT, &rw_data);
806
807                    RW_TRACE_DEBUG0 ("rw_t4t_sm_detect_ndef (): Sent RW_T4T_NDEF_DETECT_EVT");
808                }
809            }
810            else
811            {
812                /* NLEN should be less than max file size */
813                RW_TRACE_ERROR2 ("rw_t4t_sm_detect_ndef (): NLEN (%d) + 2 must be <= max file size (%d)",
814                                 nlen, p_t4t->cc_file.ndef_fc.max_file_size);
815
816                p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
817                rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
818            }
819        }
820        else
821        {
822            /* response payload size should be T4T_FILE_LENGTH_SIZE */
823            RW_TRACE_ERROR2 ("rw_t4t_sm_detect_ndef (): Length (%d) of R-APDU must be %d",
824                             p_r_apdu->len, T4T_FILE_LENGTH_SIZE + T4T_RSP_STATUS_WORDS_SIZE);
825
826            p_t4t->ndef_status &= ~ (RW_T4T_NDEF_STATUS_NDEF_DETECTED);
827            rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
828        }
829        break;
830
831    default:
832        RW_TRACE_ERROR1 ("rw_t4t_sm_detect_ndef (): unknown sub_state=%d", p_t4t->sub_state);
833        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
834        break;
835    }
836}
837
838/*******************************************************************************
839**
840** Function         rw_t4t_sm_read_ndef
841**
842** Description      State machine for NDEF read procedure
843**
844** Returns          none
845**
846*******************************************************************************/
847static void rw_t4t_sm_read_ndef (BT_HDR *p_r_apdu)
848{
849    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
850    UINT8       *p;
851    UINT16      status_words;
852    tRW_DATA    rw_data;
853
854#if (BT_TRACE_VERBOSE == TRUE)
855    RW_TRACE_DEBUG2 ("rw_t4t_sm_read_ndef (): sub_state:%s (%d)",
856                      rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
857#else
858    RW_TRACE_DEBUG1 ("rw_t4t_sm_read_ndef (): sub_state=%d", p_t4t->sub_state);
859#endif
860
861    /* get status words */
862    p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
863    p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
864    BE_STREAM_TO_UINT16 (status_words, p);
865
866    if (status_words != T4T_RSP_CMD_CMPLTED)
867    {
868        rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
869        GKI_freebuf (p_r_apdu);
870        return;
871    }
872
873    switch (p_t4t->sub_state)
874    {
875    case RW_T4T_SUBSTATE_WAIT_READ_RESP:
876
877        /* Read partial or complete data */
878        p_r_apdu->len -= T4T_RSP_STATUS_WORDS_SIZE;
879
880        if ((p_r_apdu->len > 0) && (p_r_apdu->len <= p_t4t->rw_length))
881        {
882            p_t4t->rw_length -= p_r_apdu->len;
883            p_t4t->rw_offset += p_r_apdu->len;
884
885            if (rw_cb.p_cback)
886            {
887                rw_data.data.status = NFC_STATUS_OK;
888                rw_data.data.p_data = p_r_apdu;
889
890                /* if need to read more data */
891                if (p_t4t->rw_length > 0)
892                {
893                    (*(rw_cb.p_cback)) (RW_T4T_NDEF_READ_EVT, &rw_data);
894
895                    if (!rw_t4t_read_file (p_t4t->rw_offset, p_t4t->rw_length, TRUE))
896                    {
897                        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
898                    }
899                }
900                else
901                {
902                    p_t4t->state = RW_T4T_STATE_IDLE;
903
904                    (*(rw_cb.p_cback)) (RW_T4T_NDEF_READ_CPLT_EVT, &rw_data);
905
906                    RW_TRACE_DEBUG0 ("rw_t4t_sm_read_ndef (): Sent RW_T4T_NDEF_READ_CPLT_EVT");
907
908                }
909
910                p_r_apdu = NULL;
911            }
912            else
913            {
914                p_t4t->rw_length = 0;
915                p_t4t->state = RW_T4T_STATE_IDLE;
916            }
917        }
918        else
919        {
920            RW_TRACE_ERROR2 ("rw_t4t_sm_read_ndef (): invalid payload length (%d), rw_length (%d)",
921                             p_r_apdu->len, p_t4t->rw_length);
922            rw_t4t_handle_error (NFC_STATUS_BAD_RESP, 0, 0);
923        }
924        break;
925
926    default:
927        RW_TRACE_ERROR1 ("rw_t4t_sm_read_ndef (): unknown sub_state = %d", p_t4t->sub_state);
928        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
929        break;
930    }
931
932    if (p_r_apdu)
933        GKI_freebuf (p_r_apdu);
934}
935
936/*******************************************************************************
937**
938** Function         rw_t4t_sm_update_ndef
939**
940** Description      State machine for NDEF update procedure
941**
942** Returns          none
943**
944*******************************************************************************/
945static void rw_t4t_sm_update_ndef (BT_HDR  *p_r_apdu)
946{
947    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
948    UINT8       *p;
949    UINT16      status_words;
950    tRW_DATA    rw_data;
951
952#if (BT_TRACE_VERBOSE == TRUE)
953    RW_TRACE_DEBUG2 ("rw_t4t_sm_update_ndef (): sub_state:%s (%d)",
954                      rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
955#else
956    RW_TRACE_DEBUG1 ("rw_t4t_sm_update_ndef (): sub_state=%d", p_t4t->sub_state);
957#endif
958
959    /* Get status words */
960    p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
961    p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
962    BE_STREAM_TO_UINT16 (status_words, p);
963
964    if (status_words != T4T_RSP_CMD_CMPLTED)
965    {
966        rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
967        return;
968    }
969
970    switch (p_t4t->sub_state)
971    {
972    case RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN:
973
974        /* NLEN has been updated */
975        /* if need to update data */
976        if (p_t4t->p_update_data)
977        {
978            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_RESP;
979
980            if (!rw_t4t_update_file ())
981            {
982                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
983                p_t4t->p_update_data = NULL;
984            }
985        }
986        else
987        {
988            p_t4t->state = RW_T4T_STATE_IDLE;
989
990            /* just finished last step of updating (updating NLEN) */
991            if (rw_cb.p_cback)
992            {
993                rw_data.status = NFC_STATUS_OK;
994
995                (*(rw_cb.p_cback)) (RW_T4T_NDEF_UPDATE_CPLT_EVT, &rw_data);
996                RW_TRACE_DEBUG0 ("rw_t4t_sm_update_ndef (): Sent RW_T4T_NDEF_UPDATE_CPLT_EVT");
997            }
998        }
999        break;
1000
1001    case RW_T4T_SUBSTATE_WAIT_UPDATE_RESP:
1002
1003        /* if updating is not completed */
1004        if (p_t4t->rw_length > 0)
1005        {
1006            if (!rw_t4t_update_file ())
1007            {
1008                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1009                p_t4t->p_update_data = NULL;
1010            }
1011        }
1012        else
1013        {
1014            p_t4t->p_update_data = NULL;
1015
1016            /* update NLEN as last step of updating file */
1017            if (!rw_t4t_update_nlen (p_t4t->ndef_length))
1018            {
1019                rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1020            }
1021            else
1022            {
1023                p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN;
1024            }
1025        }
1026        break;
1027
1028    default:
1029        RW_TRACE_ERROR1 ("rw_t4t_sm_update_ndef (): unknown sub_state = %d", p_t4t->sub_state);
1030        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1031        break;
1032    }
1033}
1034
1035/*******************************************************************************
1036**
1037** Function         rw_t4t_sm_set_readonly
1038**
1039** Description      State machine for CC update procedure
1040**
1041** Returns          none
1042**
1043*******************************************************************************/
1044static void rw_t4t_sm_set_readonly (BT_HDR  *p_r_apdu)
1045{
1046    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
1047    UINT8       *p;
1048    UINT16      status_words;
1049    tRW_DATA    rw_data;
1050
1051#if (BT_TRACE_VERBOSE == TRUE)
1052    RW_TRACE_DEBUG2 ("rw_t4t_sm_set_readonly (): sub_state:%s (%d)",
1053                      rw_t4t_get_sub_state_name (p_t4t->sub_state), p_t4t->sub_state);
1054#else
1055    RW_TRACE_DEBUG1 ("rw_t4t_sm_set_readonly (): sub_state=%d", p_t4t->sub_state);
1056#endif
1057
1058    /* Get status words */
1059    p = (UINT8 *) (p_r_apdu + 1) + p_r_apdu->offset;
1060    p += (p_r_apdu->len - T4T_RSP_STATUS_WORDS_SIZE);
1061    BE_STREAM_TO_UINT16 (status_words, p);
1062
1063    if (status_words != T4T_RSP_CMD_CMPLTED)
1064    {
1065        rw_t4t_handle_error (NFC_STATUS_CMD_NOT_CMPLTD, *(p-2), *(p-1));
1066        return;
1067    }
1068
1069    switch (p_t4t->sub_state)
1070    {
1071    case RW_T4T_SUBSTATE_WAIT_SELECT_CC:
1072
1073        /* CC file has been selected then update write access to read-only in CC file */
1074        if (!rw_t4t_update_cc_to_readonly ())
1075        {
1076            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1077        }
1078        else
1079        {
1080            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_CC;
1081        }
1082        break;
1083
1084    case RW_T4T_SUBSTATE_WAIT_UPDATE_CC:
1085        /* CC Updated, Select NDEF File to allow NDEF operation */
1086        p_t4t->cc_file.ndef_fc.write_access = T4T_FC_NO_WRITE_ACCESS;
1087        p_t4t->ndef_status |= RW_T4T_NDEF_STATUS_NDEF_READ_ONLY;
1088
1089        if (!rw_t4t_select_file (p_t4t->cc_file.ndef_fc.file_id))
1090        {
1091            rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1092        }
1093        else
1094        {
1095            p_t4t->sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE;
1096        }
1097        break;
1098
1099    case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE:
1100        p_t4t->state = RW_T4T_STATE_IDLE;
1101        /* just finished last step of configuring tag read only (Selecting NDEF file CC) */
1102        if (rw_cb.p_cback)
1103        {
1104            rw_data.status = NFC_STATUS_OK;
1105
1106            RW_TRACE_DEBUG0 ("rw_t4t_sm_set_readonly (): Sent RW_T4T_SET_TO_RO_EVT");
1107            (*(rw_cb.p_cback)) (RW_T4T_SET_TO_RO_EVT, &rw_data);
1108        }
1109        break;
1110
1111    default:
1112        RW_TRACE_ERROR1 ("rw_t4t_sm_set_readonly (): unknown sub_state = %d", p_t4t->sub_state);
1113        rw_t4t_handle_error (NFC_STATUS_FAILED, 0, 0);
1114        break;
1115    }
1116}
1117
1118/*******************************************************************************
1119**
1120** Function         rw_t4t_process_timeout
1121**
1122** Description      process timeout event
1123**
1124** Returns          none
1125**
1126*******************************************************************************/
1127void rw_t4t_process_timeout (TIMER_LIST_ENT *p_tle)
1128{
1129    RW_TRACE_DEBUG1 ("rw_t4t_process_timeout () event=%d", p_tle->event);
1130
1131    if (p_tle->event == NFC_TTYPE_RW_T4T_RESPONSE)
1132    {
1133        rw_t4t_handle_error (NFC_STATUS_TIMEOUT, 0, 0);
1134    }
1135    else
1136    {
1137        RW_TRACE_ERROR1 ("rw_t4t_process_timeout () unknown event=%d", p_tle->event);
1138    }
1139}
1140
1141/*******************************************************************************
1142**
1143** Function         rw_t4t_data_cback
1144**
1145** Description      This callback function receives the data from NFCC.
1146**
1147** Returns          none
1148**
1149*******************************************************************************/
1150static void rw_t4t_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_data)
1151{
1152    tRW_T4T_CB *p_t4t    = &rw_cb.tcb.t4t;
1153    BT_HDR     *p_r_apdu;
1154    tRW_DATA    rw_data;
1155
1156#if (BT_TRACE_VERBOSE == TRUE)
1157    UINT8  begin_state   = p_t4t->state;
1158#endif
1159
1160    RW_TRACE_DEBUG1 ("rw_t4t_data_cback () event = 0x%X", event);
1161    nfc_stop_quick_timer (&p_t4t->timer);
1162
1163    switch (event)
1164    {
1165    case NFC_DEACTIVATE_CEVT:
1166        NFC_SetStaticRfCback (NULL);
1167        p_t4t->state = RW_T4T_STATE_NOT_ACTIVATED;
1168        return;
1169
1170    case NFC_ERROR_CEVT:
1171        rw_data.status = (tNFC_STATUS) (*(UINT8*) p_data);
1172
1173        if (p_t4t->state != RW_T4T_STATE_IDLE)
1174        {
1175            rw_t4t_handle_error (rw_data.status, 0, 0);
1176        }
1177        else
1178        {
1179            (*(rw_cb.p_cback)) (RW_T4T_INTF_ERROR_EVT, &rw_data);
1180        }
1181        return;
1182
1183    case NFC_DATA_CEVT:
1184        p_r_apdu = (BT_HDR *) p_data->data.p_data;
1185        break;
1186
1187    default:
1188        return;
1189    }
1190
1191#if (BT_TRACE_PROTOCOL == TRUE)
1192    DispRWT4Tags (p_r_apdu, TRUE);
1193#endif
1194
1195#if (BT_TRACE_VERBOSE == TRUE)
1196    RW_TRACE_DEBUG2 ("RW T4T state: <%s (%d)>",
1197                        rw_t4t_get_state_name (p_t4t->state), p_t4t->state);
1198#else
1199    RW_TRACE_DEBUG1 ("RW T4T state: %d", p_t4t->state);
1200#endif
1201
1202    switch (p_t4t->state)
1203    {
1204    case RW_T4T_STATE_IDLE:
1205        /* Unexpected R-APDU, it should be raw frame response */
1206        /* forward to upper layer without parsing */
1207        if (rw_cb.p_cback)
1208        {
1209            rw_data.raw_frame.status = NFC_STATUS_OK;
1210            rw_data.raw_frame.p_data = p_r_apdu;
1211            (*(rw_cb.p_cback)) (RW_T4T_RAW_FRAME_EVT, &rw_data);
1212            p_r_apdu = NULL;
1213        }
1214        else
1215        {
1216            GKI_freebuf (p_r_apdu);
1217        }
1218        break;
1219    case RW_T4T_STATE_DETECT_NDEF:
1220        rw_t4t_sm_detect_ndef (p_r_apdu);
1221        GKI_freebuf (p_r_apdu);
1222        break;
1223    case RW_T4T_STATE_READ_NDEF:
1224        rw_t4t_sm_read_ndef (p_r_apdu);
1225        /* p_r_apdu may send upper lyaer */
1226        break;
1227    case RW_T4T_STATE_UPDATE_NDEF:
1228        rw_t4t_sm_update_ndef (p_r_apdu);
1229        GKI_freebuf (p_r_apdu);
1230        break;
1231    case RW_T4T_STATE_PRESENCE_CHECK:
1232        /* if any response, send presence check with ok */
1233        rw_data.status = NFC_STATUS_OK;
1234        p_t4t->state = RW_T4T_STATE_IDLE;
1235        (*(rw_cb.p_cback)) (RW_T4T_PRESENCE_CHECK_EVT, &rw_data);
1236        GKI_freebuf (p_r_apdu);
1237        break;
1238    case RW_T4T_STATE_SET_READ_ONLY:
1239        rw_t4t_sm_set_readonly (p_r_apdu);
1240        GKI_freebuf (p_r_apdu);
1241        break;
1242    default:
1243        RW_TRACE_ERROR1 ("rw_t4t_data_cback (): invalid state=%d", p_t4t->state);
1244        GKI_freebuf (p_r_apdu);
1245        break;
1246    }
1247
1248#if (BT_TRACE_VERBOSE == TRUE)
1249    if (begin_state != p_t4t->state)
1250    {
1251        RW_TRACE_DEBUG2 ("RW T4T state changed:<%s> -> <%s>",
1252                          rw_t4t_get_state_name (begin_state),
1253                          rw_t4t_get_state_name (p_t4t->state));
1254    }
1255#endif
1256}
1257
1258
1259/*******************************************************************************
1260**
1261** Function         rw_t4t_select
1262**
1263** Description      Initialise T4T
1264**
1265** Returns          NFC_STATUS_OK if success
1266**
1267*******************************************************************************/
1268tNFC_STATUS rw_t4t_select (void)
1269{
1270    tRW_T4T_CB  *p_t4t = &rw_cb.tcb.t4t;
1271
1272    RW_TRACE_DEBUG0 ("rw_t4t_select ()");
1273
1274    NFC_SetStaticRfCback (rw_t4t_data_cback);
1275
1276    p_t4t->state   = RW_T4T_STATE_IDLE;
1277    p_t4t->version = T4T_MY_VERSION;
1278
1279    /* set it min of max R-APDU data size before reading CC file */
1280    p_t4t->cc_file.max_le = T4T_MIN_MLE;
1281
1282    /* These will be udated during NDEF detection */
1283    p_t4t->max_read_size   = T4T_MAX_LENGTH_LE;
1284    p_t4t->max_update_size = T4T_MAX_LENGTH_LC;
1285
1286    return NFC_STATUS_OK;
1287}
1288
1289/*******************************************************************************
1290**
1291** Function         RW_T4tDetectNDef
1292**
1293** Description      This function performs NDEF detection procedure
1294**
1295**                  RW_T4T_NDEF_DETECT_EVT will be returned
1296**
1297** Returns          NFC_STATUS_OK if success
1298**                  NFC_STATUS_FAILED if T4T is busy or other error
1299**
1300*******************************************************************************/
1301tNFC_STATUS RW_T4tDetectNDef (void)
1302{
1303    RW_TRACE_API0 ("RW_T4tDetectNDef ()");
1304
1305    if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
1306    {
1307        RW_TRACE_ERROR1 ("RW_T4tDetectNDef ():Unable to start command at state (0x%X)",
1308                          rw_cb.tcb.t4t.state);
1309        return NFC_STATUS_FAILED;
1310    }
1311
1312    if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
1313    {
1314        /* NDEF Tag application has been selected then select CC file */
1315        if (!rw_t4t_select_file (T4T_CC_FILE_ID))
1316        {
1317            return NFC_STATUS_FAILED;
1318        }
1319        rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_CC;
1320    }
1321    else
1322    {
1323        /* Select NDEF Tag Application */
1324        if (!rw_t4t_select_application (rw_cb.tcb.t4t.version))
1325        {
1326            return NFC_STATUS_FAILED;
1327        }
1328        rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_APP;
1329    }
1330
1331    rw_cb.tcb.t4t.state     = RW_T4T_STATE_DETECT_NDEF;
1332
1333    return NFC_STATUS_OK;
1334}
1335
1336/*******************************************************************************
1337**
1338** Function         RW_T4tReadNDef
1339**
1340** Description      This function performs NDEF read procedure
1341**                  Note: RW_T4tDetectNDef () must be called before using this
1342**
1343**                  The following event will be returned
1344**                      RW_T4T_NDEF_READ_EVT for each segmented NDEF message
1345**                      RW_T4T_NDEF_READ_CPLT_EVT for the last segment or complete NDEF
1346**                      RW_T4T_NDEF_READ_FAIL_EVT for failure
1347**
1348** Returns          NFC_STATUS_OK if success
1349**                  NFC_STATUS_FAILED if T4T is busy or other error
1350**
1351*******************************************************************************/
1352tNFC_STATUS RW_T4tReadNDef (void)
1353{
1354    RW_TRACE_API0 ("RW_T4tReadNDef ()");
1355
1356    if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
1357    {
1358        RW_TRACE_ERROR1 ("RW_T4tReadNDef ():Unable to start command at state (0x%X)",
1359                          rw_cb.tcb.t4t.state);
1360        return NFC_STATUS_FAILED;
1361    }
1362
1363    /* if NDEF has been detected */
1364    if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
1365    {
1366        /* start reading NDEF */
1367        if (!rw_t4t_read_file (T4T_FILE_LENGTH_SIZE, rw_cb.tcb.t4t.ndef_length, FALSE))
1368        {
1369            return NFC_STATUS_FAILED;
1370        }
1371
1372        rw_cb.tcb.t4t.state     = RW_T4T_STATE_READ_NDEF;
1373        rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_READ_RESP;
1374
1375        return NFC_STATUS_OK;
1376    }
1377    else
1378    {
1379        RW_TRACE_ERROR0 ("RW_T4tReadNDef ():No NDEF detected");
1380        return NFC_STATUS_FAILED;
1381    }
1382}
1383
1384/*******************************************************************************
1385**
1386** Function         RW_T4tUpdateNDef
1387**
1388** Description      This function performs NDEF update procedure
1389**                  Note: RW_T4tDetectNDef () must be called before using this
1390**                        Updating data must not be removed until returning event
1391**
1392**                  The following event will be returned
1393**                      RW_T4T_NDEF_UPDATE_CPLT_EVT for complete
1394**                      RW_T4T_NDEF_UPDATE_FAIL_EVT for failure
1395**
1396** Returns          NFC_STATUS_OK if success
1397**                  NFC_STATUS_FAILED if T4T is busy or other error
1398**
1399*******************************************************************************/
1400tNFC_STATUS RW_T4tUpdateNDef (UINT16 length, UINT8 *p_data)
1401{
1402    RW_TRACE_API1 ("RW_T4tUpdateNDef () length:%d", length);
1403
1404    if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
1405    {
1406        RW_TRACE_ERROR1 ("RW_T4tUpdateNDef ():Unable to start command at state (0x%X)",
1407                          rw_cb.tcb.t4t.state);
1408        return NFC_STATUS_FAILED;
1409    }
1410
1411    /* if NDEF has been detected */
1412    if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
1413    {
1414        /* if read-only */
1415        if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_READ_ONLY)
1416        {
1417            RW_TRACE_ERROR0 ("RW_T4tUpdateNDef ():NDEF is read-only");
1418            return NFC_STATUS_FAILED;
1419        }
1420
1421        if (rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size < length + T4T_FILE_LENGTH_SIZE)
1422        {
1423            RW_TRACE_ERROR2 ("RW_T4tUpdateNDef ():data (%d bytes) plus NLEN is more than max file size (%d)",
1424                              length, rw_cb.tcb.t4t.cc_file.ndef_fc.max_file_size);
1425            return NFC_STATUS_FAILED;
1426        }
1427
1428        /* store NDEF length and data */
1429        rw_cb.tcb.t4t.ndef_length   = length;
1430        rw_cb.tcb.t4t.p_update_data = p_data;
1431
1432        rw_cb.tcb.t4t.rw_offset     = T4T_FILE_LENGTH_SIZE;
1433        rw_cb.tcb.t4t.rw_length     = length;
1434
1435        /* set NLEN to 0x0000 for the first step */
1436        if (!rw_t4t_update_nlen (0x0000))
1437        {
1438            return NFC_STATUS_FAILED;
1439        }
1440
1441        rw_cb.tcb.t4t.state     = RW_T4T_STATE_UPDATE_NDEF;
1442        rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN;
1443
1444        return NFC_STATUS_OK;
1445    }
1446    else
1447    {
1448        RW_TRACE_ERROR0 ("RW_T4tUpdateNDef ():No NDEF detected");
1449        return NFC_STATUS_FAILED;
1450    }
1451}
1452
1453/*****************************************************************************
1454**
1455** Function         RW_T4tPresenceCheck
1456**
1457** Description
1458**      Check if the tag is still in the field.
1459**
1460**      The RW_T4T_PRESENCE_CHECK_EVT w/ status is used to indicate presence
1461**      or non-presence.
1462**
1463** Returns
1464**      NFC_STATUS_OK, if raw data frame sent
1465**      NFC_STATUS_NO_BUFFERS: unable to allocate a buffer for this operation
1466**      NFC_STATUS_FAILED: other error
1467**
1468*****************************************************************************/
1469tNFC_STATUS RW_T4tPresenceCheck (void)
1470{
1471    tNFC_STATUS retval = NFC_STATUS_OK;
1472    tRW_DATA    evt_data;
1473
1474    RW_TRACE_API0 ("RW_T4tPresenceCheck ()");
1475
1476    /* If RW_SelectTagType was not called (no conn_callback) return failure */
1477    if (!rw_cb.p_cback)
1478    {
1479        retval = NFC_STATUS_FAILED;
1480    }
1481    /* If we are not activated, then RW_T4T_PRESENCE_CHECK_EVT with NFC_STATUS_FAILED */
1482    else if (rw_cb.tcb.t4t.state == RW_T4T_STATE_NOT_ACTIVATED)
1483    {
1484        evt_data.status = NFC_STATUS_FAILED;
1485        (*rw_cb.p_cback) (RW_T4T_PRESENCE_CHECK_EVT, &evt_data);
1486    }
1487    /* If command is pending, assume tag is still present */
1488    else if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
1489    {
1490        evt_data.status = NFC_STATUS_OK;
1491        (*rw_cb.p_cback) (RW_T4T_PRESENCE_CHECK_EVT, &evt_data);
1492    }
1493    else
1494    {
1495        if (rw_t4t_read_file (0, 1, FALSE))
1496        {
1497            rw_cb.tcb.t4t.state = RW_T4T_STATE_PRESENCE_CHECK;
1498        }
1499        else
1500        {
1501            retval = NFC_STATUS_NO_BUFFERS;
1502        }
1503    }
1504
1505    return (retval);
1506}
1507
1508/*****************************************************************************
1509**
1510** Function         RW_T4tSetNDefReadOnly
1511**
1512** Description      This function performs NDEF read-only procedure
1513**                  Note: RW_T4tDetectNDef() must be called before using this
1514**
1515**                  The RW_T4T_SET_TO_RO_EVT event will be returned.
1516**
1517** Returns          NFC_STATUS_OK if success
1518**                  NFC_STATUS_FAILED if T4T is busy or other error
1519**
1520*****************************************************************************/
1521tNFC_STATUS RW_T4tSetNDefReadOnly (void)
1522{
1523    tNFC_STATUS retval = NFC_STATUS_OK;
1524    tRW_DATA    evt_data;
1525
1526    RW_TRACE_API0 ("RW_T4tSetNDefReadOnly ()");
1527
1528    if (rw_cb.tcb.t4t.state != RW_T4T_STATE_IDLE)
1529    {
1530        RW_TRACE_ERROR1 ("RW_T4tSetNDefReadOnly ():Unable to start command at state (0x%X)",
1531                          rw_cb.tcb.t4t.state);
1532        return NFC_STATUS_FAILED;
1533    }
1534
1535    /* if NDEF has been detected */
1536    if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_DETECTED)
1537    {
1538        /* if read-only */
1539        if (rw_cb.tcb.t4t.ndef_status & RW_T4T_NDEF_STATUS_NDEF_READ_ONLY)
1540        {
1541            RW_TRACE_API0 ("RW_T4tSetNDefReadOnly (): NDEF is already read-only");
1542
1543            evt_data.status = NFC_STATUS_OK;
1544            (*rw_cb.p_cback) (RW_T4T_SET_TO_RO_EVT, &evt_data);
1545            return (retval);
1546        }
1547
1548        /* NDEF Tag application has been selected then select CC file */
1549        if (!rw_t4t_select_file (T4T_CC_FILE_ID))
1550        {
1551            return NFC_STATUS_FAILED;
1552        }
1553
1554        rw_cb.tcb.t4t.state     = RW_T4T_STATE_SET_READ_ONLY;
1555        rw_cb.tcb.t4t.sub_state = RW_T4T_SUBSTATE_WAIT_SELECT_CC;
1556
1557        return NFC_STATUS_OK;
1558    }
1559    else
1560    {
1561        RW_TRACE_ERROR0 ("RW_T4tSetNDefReadOnly ():No NDEF detected");
1562        return NFC_STATUS_FAILED;
1563    }
1564    return (retval);
1565}
1566
1567#if (BT_TRACE_VERBOSE == TRUE)
1568/*******************************************************************************
1569**
1570** Function         rw_t4t_get_state_name
1571**
1572** Description      This function returns the state name.
1573**
1574** NOTE             conditionally compiled to save memory.
1575**
1576** Returns          pointer to the name
1577**
1578*******************************************************************************/
1579static char *rw_t4t_get_state_name (UINT8 state)
1580{
1581    switch (state)
1582    {
1583    case RW_T4T_STATE_NOT_ACTIVATED:
1584        return ("NOT_ACTIVATED");
1585    case RW_T4T_STATE_IDLE:
1586        return ("IDLE");
1587    case RW_T4T_STATE_DETECT_NDEF:
1588        return ("NDEF_DETECTION");
1589    case RW_T4T_STATE_READ_NDEF:
1590        return ("READ_NDEF");
1591    case RW_T4T_STATE_UPDATE_NDEF:
1592        return ("UPDATE_NDEF");
1593    case RW_T4T_STATE_PRESENCE_CHECK:
1594        return ("PRESENCE_CHECK");
1595    case RW_T4T_STATE_SET_READ_ONLY:
1596        return ("SET_READ_ONLY");
1597
1598    default:
1599        return ("???? UNKNOWN STATE");
1600    }
1601}
1602
1603/*******************************************************************************
1604**
1605** Function         rw_t4t_get_sub_state_name
1606**
1607** Description      This function returns the sub_state name.
1608**
1609** NOTE             conditionally compiled to save memory.
1610**
1611** Returns          pointer to the name
1612**
1613*******************************************************************************/
1614static char *rw_t4t_get_sub_state_name (UINT8 sub_state)
1615{
1616    switch (sub_state)
1617    {
1618    case RW_T4T_SUBSTATE_WAIT_SELECT_APP:
1619        return ("WAIT_SELECT_APP");
1620    case RW_T4T_SUBSTATE_WAIT_SELECT_CC:
1621        return ("WAIT_SELECT_CC");
1622    case RW_T4T_SUBSTATE_WAIT_CC_FILE:
1623        return ("WAIT_CC_FILE");
1624    case RW_T4T_SUBSTATE_WAIT_SELECT_NDEF_FILE:
1625        return ("WAIT_SELECT_NDEF_FILE");
1626    case RW_T4T_SUBSTATE_WAIT_READ_NLEN:
1627        return ("WAIT_READ_NLEN");
1628
1629    case RW_T4T_SUBSTATE_WAIT_READ_RESP:
1630        return ("WAIT_READ_RESP");
1631    case RW_T4T_SUBSTATE_WAIT_UPDATE_RESP:
1632        return ("WAIT_UPDATE_RESP");
1633    case RW_T4T_SUBSTATE_WAIT_UPDATE_NLEN:
1634        return ("WAIT_UPDATE_NLEN");
1635    default:
1636        return ("???? UNKNOWN SUBSTATE");
1637    }
1638}
1639#endif
1640
1641#endif /* (NFC_INCLUDED == TRUE) */
1642