libnfc  1.4.2
pn53x-sam.c
Go to the documentation of this file.
00001 /*-
00002  * Public platform independent Near Field Communication (NFC) library examples
00003  * 
00004  * Copyright (C) 2010, Emanuele Bertoldi
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *  1) Redistributions of source code must retain the above copyright notice,
00009  *  this list of conditions and the following disclaimer. 
00010  *  2 )Redistributions in binary form must reproduce the above copyright
00011  *  notice, this list of conditions and the following disclaimer in the
00012  *  documentation and/or other materials provided with the distribution.
00013  *
00014  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00015  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00016  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00017  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00018  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00019  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00020  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00021  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00022  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00023  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00024  * POSSIBILITY OF SUCH DAMAGE.
00025  * 
00026  * Note that this license only applies on the examples, NFC library itself is under LGPL
00027  *
00028  */
00029 
00035 #ifdef HAVE_CONFIG_H
00036 #  include "config.h"
00037 #endif // HAVE_CONFIG_H
00038 
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <time.h>
00042 
00043 #ifndef _WIN32
00044 // Needed by sleep() under Unix
00045 #  include <unistd.h>
00046 #  define sleep sleep
00047 #  define SUSP_TIME 1           // secs.
00048 #else
00049 // Needed by Sleep() under Windows
00050 #  include "../contrib/windows.h"
00051 #  include <winbase.h>
00052 #  define sleep Sleep
00053 #  define SUSP_TIME 1000        // msecs.
00054 #endif
00055 
00056 #include <nfc/nfc.h>
00057 #include <nfc/nfc-messages.h>
00058 #include "nfc-utils.h"
00059 
00060 #include "chips/pn53x.h"
00061 
00062 #define MAX_FRAME_LEN 264
00063 #define TIMEOUT 60              // secs.
00064 
00065 #define NORMAL_MODE 1
00066 #define VIRTUAL_CARD_MODE 2
00067 #define WIRED_CARD_MODE 3
00068 #define DUAL_CARD_MODE 4
00069 
00070 bool
00071 sam_connection (nfc_device_t * pnd, int mode)
00072 {
00073   byte_t  pncmd_sam_config[] = { 0xD4, 0x14, 0x00, 0x00 };
00074   size_t  szCmd = 0;
00075 
00076   byte_t  abtRx[MAX_FRAME_LEN];
00077   size_t  szRx;
00078 
00079   pncmd_sam_config[2] = mode;
00080 
00081   switch (mode) {
00082   case VIRTUAL_CARD_MODE:
00083     {
00084       // Only the VIRTUAL_CARD_MODE requires 4 bytes.
00085       szCmd = sizeof (pncmd_sam_config);
00086     }
00087     break;
00088 
00089   default:
00090     {
00091       szCmd = sizeof (pncmd_sam_config) - 1;
00092     }
00093     break;
00094   }
00095 
00096   if (!pn53x_transceive (pnd, pncmd_sam_config, szCmd, abtRx, &szRx)) {
00097     nfc_perror(pnd, "pn53x_transceive");
00098     ERR ("%s %d", "Unable to execute SAMConfiguration command with mode byte:", mode);
00099     return false;
00100   }
00101 
00102   return true;
00103 }
00104 
00105 void
00106 wait_one_minute ()
00107 {
00108   int     secs = 0;
00109 
00110   printf ("|");
00111   fflush (stdout);
00112 
00113   while (secs < TIMEOUT) {
00114     sleep (SUSP_TIME);
00115     secs++;
00116     printf (".");
00117     fflush (stdout);
00118   }
00119 
00120   printf ("|\n");
00121 }
00122 
00123 int
00124 main (int argc, const char *argv[])
00125 {
00126   nfc_device_t *pnd;
00127 
00128   (void) argc;
00129   (void) argv;
00130 
00131   // Display libnfc version
00132   const char *acLibnfcVersion = nfc_version ();
00133   printf ("%s use libnfc %s\n", argv[0], acLibnfcVersion);
00134 
00135   // Connect using the first available NFC device
00136   pnd = nfc_connect (NULL);
00137 
00138   if (pnd == NULL) {
00139     ERR ("%s", "Unable to connect to NFC device.");
00140     return EXIT_FAILURE;
00141   }
00142 
00143   printf ("Connected to NFC device: %s\n", pnd->acName);
00144 
00145   // Print the example's menu
00146   printf ("\nSelect the communication mode:\n");
00147   printf ("[1] Virtual card mode.\n");
00148   printf ("[2] Wired card mode.\n");
00149   printf ("[3] Dual card mode.\n");
00150   printf (">> ");
00151 
00152   // Take user's choice
00153   char    input = getchar ();
00154   int     mode = input - '0' + 1;
00155   printf ("\n");
00156   if (mode < VIRTUAL_CARD_MODE || mode > DUAL_CARD_MODE) {
00157     ERR ("%s", "Invalid selection.");
00158     return EXIT_FAILURE;
00159   }
00160   // Connect with the SAM
00161   sam_connection (pnd, mode);
00162 
00163   switch (mode) {
00164   case VIRTUAL_CARD_MODE:
00165     {
00166       // FIXME after the loop the device doesn't respond to host commands...
00167       printf ("Now the SAM is readable for 1 minute from an external reader.\n");
00168       wait_one_minute ();
00169     }
00170     break;
00171 
00172   case WIRED_CARD_MODE:
00173     {
00174       nfc_target_t nt;
00175 
00176       // Set connected NFC device to initiator mode
00177       nfc_initiator_init (pnd);
00178 
00179       // Drop the field for a while
00180       if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) {
00181         nfc_perror (pnd, "nfc_configure");
00182         exit (EXIT_FAILURE);
00183       }
00184       // Let the reader only try once to find a tag
00185       if (!nfc_configure (pnd, NDO_INFINITE_SELECT, false)) {
00186         nfc_perror (pnd, "nfc_configure");
00187         exit (EXIT_FAILURE);
00188       }
00189       // Enable field so more power consuming cards can power themselves up
00190       if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, true)) {
00191         nfc_perror (pnd, "nfc_configure");
00192         exit (EXIT_FAILURE);
00193       }
00194       // Read the SAM's info
00195       const nfc_modulation_t nmSAM = {
00196         .nmt = NMT_ISO14443A,
00197         .nbr = NBR_106,
00198       };
00199       if (!nfc_initiator_select_passive_target (pnd, nmSAM, NULL, 0, &nt)) {
00200         nfc_perror (pnd, "nfc_initiator_select_passive_target");
00201         ERR ("%s", "Reading of SAM info failed.");
00202         return EXIT_FAILURE;
00203       }
00204 
00205       printf ("The following ISO14443A tag (SAM) was found:\n\n");
00206       print_nfc_iso14443a_info (nt.nti.nai, true);
00207     }
00208     break;
00209 
00210   case DUAL_CARD_MODE:
00211     {
00212       byte_t  abtRx[MAX_FRAME_LEN];
00213       size_t  szRx;
00214 
00215       nfc_target_t nt = {
00216         .nm.nmt = NMT_ISO14443A,
00217         .nm.nbr = NBR_UNDEFINED,
00218         .nti.nai.abtAtqa = { 0x04, 0x00 },
00219         .nti.nai.abtUid = { 0x08, 0xad, 0xbe, 0xef },
00220         .nti.nai.btSak = 0x20,
00221         .nti.nai.szUidLen = 4,
00222         .nti.nai.szAtsLen = 0,
00223       };
00224       printf ("Now both, NFC device (configured as target) and SAM are readables from an external NFC initiator.\n");
00225       printf ("Please note that NFC device (configured as target) stay in target mode until it receive RATS, ATR_REQ or proprietary command.\n");
00226       if (!nfc_target_init (pnd, &nt, abtRx, &szRx)) {
00227         nfc_perror(pnd, "nfc_target_init");
00228         return EXIT_FAILURE;
00229       }
00230       // wait_one_minute ();
00231     }
00232     break;
00233   }
00234 
00235   // Disconnect from the SAM
00236   sam_connection (pnd, NORMAL_MODE);
00237 
00238   // Disconnect from NFC device
00239   nfc_disconnect (pnd);
00240 
00241   return EXIT_SUCCESS;
00242 }