libnfc  1.4.2
pn53x-sam.c
Go to the documentation of this file.
1 /*-
2  * Public platform independent Near Field Communication (NFC) library examples
3  *
4  * Copyright (C) 2010, Emanuele Bertoldi
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  * 1) Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2 )Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  *
26  * Note that this license only applies on the examples, NFC library itself is under LGPL
27  *
28  */
29 
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif // HAVE_CONFIG_H
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <time.h>
42 
43 #ifndef _WIN32
44 // Needed by sleep() under Unix
45 # include <unistd.h>
46 # define sleep sleep
47 # define SUSP_TIME 1 // secs.
48 #else
49 // Needed by Sleep() under Windows
50 # include "../contrib/windows.h"
51 # include <winbase.h>
52 # define sleep Sleep
53 # define SUSP_TIME 1000 // msecs.
54 #endif
55 
56 #include <nfc/nfc.h>
57 #include <nfc/nfc-messages.h>
58 #include "nfc-utils.h"
59 
60 #include "chips/pn53x.h"
61 
62 #define MAX_FRAME_LEN 264
63 #define TIMEOUT 60 // secs.
64 
65 #define NORMAL_MODE 1
66 #define VIRTUAL_CARD_MODE 2
67 #define WIRED_CARD_MODE 3
68 #define DUAL_CARD_MODE 4
69 
70 bool
71 sam_connection (nfc_device_t * pnd, int mode)
72 {
73  byte_t pncmd_sam_config[] = { 0xD4, 0x14, 0x00, 0x00 };
74  size_t szCmd = 0;
75 
76  byte_t abtRx[MAX_FRAME_LEN];
77  size_t szRx;
78 
79  pncmd_sam_config[2] = mode;
80 
81  switch (mode) {
82  case VIRTUAL_CARD_MODE:
83  {
84  // Only the VIRTUAL_CARD_MODE requires 4 bytes.
85  szCmd = sizeof (pncmd_sam_config);
86  }
87  break;
88 
89  default:
90  {
91  szCmd = sizeof (pncmd_sam_config) - 1;
92  }
93  break;
94  }
95 
96  if (!pn53x_transceive (pnd, pncmd_sam_config, szCmd, abtRx, &szRx)) {
97  nfc_perror(pnd, "pn53x_transceive");
98  ERR ("%s %d", "Unable to execute SAMConfiguration command with mode byte:", mode);
99  return false;
100  }
101 
102  return true;
103 }
104 
105 void
106 wait_one_minute ()
107 {
108  int secs = 0;
109 
110  printf ("|");
111  fflush (stdout);
112 
113  while (secs < TIMEOUT) {
114  sleep (SUSP_TIME);
115  secs++;
116  printf (".");
117  fflush (stdout);
118  }
119 
120  printf ("|\n");
121 }
122 
123 int
124 main (int argc, const char *argv[])
125 {
126  nfc_device_t *pnd;
127 
128  (void) argc;
129  (void) argv;
130 
131  // Display libnfc version
132  const char *acLibnfcVersion = nfc_version ();
133  printf ("%s use libnfc %s\n", argv[0], acLibnfcVersion);
134 
135  // Connect using the first available NFC device
136  pnd = nfc_connect (NULL);
137 
138  if (pnd == NULL) {
139  ERR ("%s", "Unable to connect to NFC device.");
140  return EXIT_FAILURE;
141  }
142 
143  printf ("Connected to NFC device: %s\n", pnd->acName);
144 
145  // Print the example's menu
146  printf ("\nSelect the communication mode:\n");
147  printf ("[1] Virtual card mode.\n");
148  printf ("[2] Wired card mode.\n");
149  printf ("[3] Dual card mode.\n");
150  printf (">> ");
151 
152  // Take user's choice
153  char input = getchar ();
154  int mode = input - '0' + 1;
155  printf ("\n");
156  if (mode < VIRTUAL_CARD_MODE || mode > DUAL_CARD_MODE) {
157  ERR ("%s", "Invalid selection.");
158  return EXIT_FAILURE;
159  }
160  // Connect with the SAM
161  sam_connection (pnd, mode);
162 
163  switch (mode) {
164  case VIRTUAL_CARD_MODE:
165  {
166  // FIXME after the loop the device doesn't respond to host commands...
167  printf ("Now the SAM is readable for 1 minute from an external reader.\n");
168  wait_one_minute ();
169  }
170  break;
171 
172  case WIRED_CARD_MODE:
173  {
174  nfc_target_t nt;
175 
176  // Set connected NFC device to initiator mode
177  nfc_initiator_init (pnd);
178 
179  // Drop the field for a while
180  if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) {
181  nfc_perror (pnd, "nfc_configure");
182  exit (EXIT_FAILURE);
183  }
184  // Let the reader only try once to find a tag
185  if (!nfc_configure (pnd, NDO_INFINITE_SELECT, false)) {
186  nfc_perror (pnd, "nfc_configure");
187  exit (EXIT_FAILURE);
188  }
189  // Enable field so more power consuming cards can power themselves up
190  if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, true)) {
191  nfc_perror (pnd, "nfc_configure");
192  exit (EXIT_FAILURE);
193  }
194  // Read the SAM's info
195  const nfc_modulation_t nmSAM = {
196  .nmt = NMT_ISO14443A,
197  .nbr = NBR_106,
198  };
199  if (!nfc_initiator_select_passive_target (pnd, nmSAM, NULL, 0, &nt)) {
200  nfc_perror (pnd, "nfc_initiator_select_passive_target");
201  ERR ("%s", "Reading of SAM info failed.");
202  return EXIT_FAILURE;
203  }
204 
205  printf ("The following ISO14443A tag (SAM) was found:\n\n");
206  print_nfc_iso14443a_info (nt.nti.nai, true);
207  }
208  break;
209 
210  case DUAL_CARD_MODE:
211  {
212  byte_t abtRx[MAX_FRAME_LEN];
213  size_t szRx;
214 
215  nfc_target_t nt = {
216  .nm.nmt = NMT_ISO14443A,
217  .nm.nbr = NBR_UNDEFINED,
218  .nti.nai.abtAtqa = { 0x04, 0x00 },
219  .nti.nai.abtUid = { 0x08, 0xad, 0xbe, 0xef },
220  .nti.nai.btSak = 0x20,
221  .nti.nai.szUidLen = 4,
222  .nti.nai.szAtsLen = 0,
223  };
224  printf ("Now both, NFC device (configured as target) and SAM are readables from an external NFC initiator.\n");
225  printf ("Please note that NFC device (configured as target) stay in target mode until it receive RATS, ATR_REQ or proprietary command.\n");
226  if (!nfc_target_init (pnd, &nt, abtRx, &szRx)) {
227  nfc_perror(pnd, "nfc_target_init");
228  return EXIT_FAILURE;
229  }
230  // wait_one_minute ();
231  }
232  break;
233  }
234 
235  // Disconnect from the SAM
236  sam_connection (pnd, NORMAL_MODE);
237 
238  // Disconnect from NFC device
239  nfc_disconnect (pnd);
240 
241  return EXIT_SUCCESS;
242 }