/*-
 * Public platform independent Near Field Communication (NFC) library examples
 * 
 * Copyright (C) 2009, Roel Verdult
 * Copyright (C) 2010, Romuald Conty, Romain Tartière
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *  1) Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer. 
 *  2 )Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Note that this license only applies on the examples, NFC library itself is under LGPL
 *
 */
/**
 * @file nfc-utils.c
 * @brief Provide some examples shared functions like print, parity calculation, options parsing.
 */
#include <nfc/nfc.h>
#include <err.h>

#include "nfc-utils.h"

struct card_atqa
{
    uint16_t atqa;
    uint16_t mask;
    char type[128];
    // list of up to 8 SAK values compatible with this ATQA
    int saklist[8];
};

struct card_sak
{
    uint8_t sak;
    uint8_t mask;
    char type[128];
};

struct card_atqa const_ca[] = {
    {0x0044, 0xffff, "MIFARE Ultralight",
      {0, -1} },
    {0x0044, 0xffff, "MIFARE Ultralight C",
      {0, -1} },
    {0x0004, 0xff0f, "MIFARE Mini 0.3K",
      {1, -1} },
    {0x0004, 0xff0f, "MIFARE Classic 1K",
      {2, -1} },
    {0x0002, 0xff0f, "MIFARE Classic 4K",
      {3, -1} },
    {0x0004, 0xffff, "MIFARE Plus (4 Byte UID or 4 Byte RID)",
      {4, 5, 6, 7, 8, 9, -1} },
    {0x0002, 0xffff, "MIFARE Plus (4 Byte UID or 4 Byte RID)",
      {4, 5, 6, 7, 8, 9, -1} },
    {0x0044, 0xffff, "MIFARE Plus (7 Byte UID)",
      {4, 5, 6, 7, 8, 9, -1} },
    {0x0042, 0xffff, "MIFARE Plus (7 Byte UID)",
      {4, 5, 6, 7, 8, 9, -1} },
    {0x0344, 0xffff, "MIFARE DESFire",
      {10, 11, -1} },
    {0x0044, 0xffff, "P3SR008",
      {-1} }, // TODO we need SAK info
    {0x0004, 0xf0ff, "SmartMX with MIFARE 1K emulation",
      {12, -1} },
    {0x0002, 0xf0ff, "SmartMX with MIFARE 4K emulation",
      {12, -1} },
    {0x0048, 0xf0ff, "SmartMX with 7 Byte UID",
      {12, -1} }
};

struct card_sak const_cs[] = {
    {0x00, 0xff, "" },                      // 00 MIFARE Ultralight / Ultralight C
    {0x09, 0xff, "" },                      // 01 MIFARE Mini 0.3K
    {0x08, 0xff, "" },                      // 02 MIFARE Classic 1K
    {0x18, 0xff, "" },                      // 03 MIFARE Classik 4K
    {0x08, 0xff, " 2K, Security level 1" }, // 04 MIFARE Plus
    {0x18, 0xff, " 4K, Security level 1" }, // 05 MIFARE Plus
    {0x10, 0xff, " 2K, Security level 2" }, // 06 MIFARE Plus
    {0x11, 0xff, " 4K, Security level 2" }, // 07 MIFARE Plus
    {0x20, 0xff, " 2K, Security level 3" }, // 08 MIFARE Plus
    {0x20, 0xff, " 4K, Security level 3" }, // 09 MIFARE Plus
    {0x20, 0xff, " 4K" },                   // 10 MIFARE DESFire
    {0x20, 0xff, " EV1 2K/4K/8K" },         // 11 MIFARE DESFire
    {0x00, 0x00, "" },                      // 12 SmartMX
};

uint8_t
oddparity (const uint8_t bt)
{
  // cf http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
  return (0x9669 >> ((bt ^ (bt >> 4)) & 0xF)) & 1;
}

void
oddparity_bytes_ts (const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar)
{
  size_t  szByteNr;
  // Calculate the parity bits for the command
  for (szByteNr = 0; szByteNr < szLen; szByteNr++) {
    pbtPar[szByteNr] = oddparity(pbtData[szByteNr]);
  }
}

void
print_hex (const uint8_t *pbtData, const size_t szBytes)
{
  size_t  szPos;

  for (szPos = 0; szPos < szBytes; szPos++) {
    printf ("%02x  ", pbtData[szPos]);
  }
  printf ("\n");
}

void
print_hex_bits (const uint8_t *pbtData, const size_t szBits)
{
  uint8_t uRemainder;
  size_t  szPos;
  size_t  szBytes = szBits / 8;

  for (szPos = 0; szPos < szBytes; szPos++) {
    printf ("%02x  ", pbtData[szPos]);
  }

  uRemainder = szBits % 8;
  // Print the rest bits
  if (uRemainder != 0) {
    if (uRemainder < 5)
      printf ("%01x (%d bits)", pbtData[szBytes], uRemainder);
    else
      printf ("%02x (%d bits)", pbtData[szBytes], uRemainder);
  }
  printf ("\n");
}

void
print_hex_par (const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar)
{
  uint8_t uRemainder;
  size_t  szPos;
  size_t  szBytes = szBits / 8;

  for (szPos = 0; szPos < szBytes; szPos++) {
    printf ("%02x", pbtData[szPos]);
    if (oddparity(pbtData[szPos]) != pbtDataPar[szPos]) {
      printf ("! ");
    } else {
      printf ("  ");
    }
  }

  uRemainder = szBits % 8;
  // Print the rest bits, these cannot have parity bit
  if (uRemainder != 0) {
    if (uRemainder < 5)
      printf ("%01x (%d bits)", pbtData[szBytes], uRemainder);
    else
      printf ("%02x (%d bits)", pbtData[szBytes], uRemainder);
  }
  printf ("\n");
}

#define SAK_UID_NOT_COMPLETE     0x04
#define SAK_ISO14443_4_COMPLIANT 0x20
#define SAK_ISO18092_COMPLIANT   0x40

void
print_nfc_iso14443a_info (const nfc_iso14443a_info nai, bool verbose)
{
  printf ("    ATQA (SENS_RES): ");
  print_hex (nai.abtAtqa, 2);
  if (verbose) {
    printf("* UID size: ");
    switch ((nai.abtAtqa[1] & 0xc0)>>6) {
      case 0:
        printf("single\n");
      break;
      case 1:
        printf("double\n");
      break;
      case 2:
        printf("triple\n");
      break;
      case 3:
        printf("RFU\n");
      break;
    }
    printf("* bit frame anticollision ");
    switch (nai.abtAtqa[1] & 0x1f) {
      case 0x01:
      case 0x02:
      case 0x04:
      case 0x08:
      case 0x10:
        printf("supported\n");
      break;
      default:
        printf("not supported\n");
      break;
    }
  }
  printf ("       UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1'));
  print_hex (nai.abtUid, nai.szUidLen);
  if (verbose) {
    if (nai.abtUid[0] == 0x08) {
      printf ("* Random UID\n");
    }
  }
  printf ("      SAK (SEL_RES): ");
  print_hex (&nai.btSak, 1);
  if (verbose) {
    if (nai.btSak & SAK_UID_NOT_COMPLETE) {
      printf ("* Warning! Cascade bit set: UID not complete\n");
    }
    if (nai.btSak & SAK_ISO14443_4_COMPLIANT) {
      printf ("* Compliant with ISO/IEC 14443-4\n");
    } else {
      printf ("* Not compliant with ISO/IEC 14443-4\n");
    }
    if (nai.btSak & SAK_ISO18092_COMPLIANT) {
      printf ("* Compliant with ISO/IEC 18092\n");
    } else {
      printf ("* Not compliant with ISO/IEC 18092\n");
    }
  }
  if (nai.szAtsLen) {
    printf ("                ATS: ");
    print_hex (nai.abtAts, nai.szAtsLen);
  }
  if (nai.szAtsLen && verbose) {
    // Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select)
    const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
    printf ("* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]);

    size_t offset = 1;
    if (nai.abtAts[0] & 0x10) { // TA(1) present
      uint8_t TA = nai.abtAts[offset];
      offset++;
      printf ("* Bit Rate Capability:\n");
      if (TA == 0) {
        printf ("  * PICC supports only 106 kbits/s in both directions\n");
      }
      if (TA & 1<<7) {
        printf ("  * Same bitrate in both directions mandatory\n");
      }
      if (TA & 1<<4) {
        printf ("  * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n");
      }
      if (TA & 1<<5) {
        printf ("  * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n");
      }
      if (TA & 1<<6) {
        printf ("  * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n");
      }
      if (TA & 1<<0) {
        printf ("  * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n");
      }
      if (TA & 1<<1) {
        printf ("  * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n");
      }
      if (TA & 1<<2) {
        printf ("  * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n");
      }
      if (TA & 1<<3) {
        printf ("  * ERROR unknown value\n");
      }
    }
    if (nai.abtAts[0] & 0x20) { // TB(1) present
      uint8_t TB= nai.abtAts[offset];
      offset++;
      printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((TB & 0xf0) >> 4))/13560.0);
      if ((TB & 0x0f) == 0) {
        printf ("* No Start-up Frame Guard Time required\n");
      } else {
        printf ("* Start-up Frame Guard Time: %.4g ms\n",256.0*16.0*(1<<(TB & 0x0f))/13560.0);
      }
    }
    if (nai.abtAts[0] & 0x40) { // TC(1) present
      uint8_t TC = nai.abtAts[offset];
      offset++;
      if (TC & 0x1) {
        printf("* Node ADdress supported\n");
      } else {
        printf("* Node ADdress not supported\n");
      }
      if (TC & 0x2) {
        printf("* Card IDentifier supported\n");
      } else {
        printf("* Card IDentifier not supported\n");
      }
    }
    if (nai.szAtsLen > offset) {
      printf ("* Historical bytes Tk: " );
      print_hex (nai.abtAts + offset, (nai.szAtsLen - offset));
      uint8_t CIB = nai.abtAts[offset];
      offset++;
      if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) {
        printf("  * Proprietary format\n");
        if (CIB == 0xc1) {
          printf("    * Tag byte: Mifare or virtual cards of various types\n");
          uint8_t L = nai.abtAts[offset];
          offset++;
          if (L != (nai.szAtsLen - offset)) {
            printf("    * Warning: Type Identification Coding length (%i)", L);
            printf(" not matching Tk length (%zi)\n", (nai.szAtsLen - offset));
          }
          if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes
            uint8_t CTC = nai.abtAts[offset];
            offset++;
            printf("    * Chip Type: ");
            switch (CTC & 0xf0) {
              case 0x00:
                printf("(Multiple) Virtual Cards\n");
              break;
              case 0x10:
                printf("Mifare DESFire\n");
              break;
              case 0x20:
                printf("Mifare Plus\n");
              break;
              default:
                printf("RFU\n");
              break;
            }
            printf("    * Memory size: ");
            switch (CTC & 0x0f) {
              case 0x00:
                printf("<1 kbyte\n");
              break;
              case 0x01:
                printf("1 kbyte\n");
              break;
              case 0x02:
                printf("2 kbyte\n");
              break;
              case 0x03:
                printf("4 kbyte\n");
              break;
              case 0x04:
                printf("8 kbyte\n");
              break;
              case 0x0f:
                printf("Unspecified\n");
              break;
              default:
                printf("RFU\n");
              break;
            }
          }
          if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
            uint8_t CVC = nai.abtAts[offset];
            offset++;
            printf("    * Chip Status: ");
            switch (CVC & 0xf0) {
              case 0x00:
                printf("Engineering sample\n");
              break;
              case 0x20:
                printf("Released\n");
              break;
              default:
                printf("RFU\n");
              break;
            }
            printf("    * Chip Generation: ");
            switch (CVC & 0x0f) {
              case 0x00:
                printf("Generation 1\n");
              break;
              case 0x01:
                printf("Generation 2\n");
              break;
              case 0x02:
                printf("Generation 3\n");
              break;
              case 0x0f:
                printf("Unspecified\n");
              break;
              default:
                printf("RFU\n");
              break;
            }
          }
          if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
            uint8_t VCS = nai.abtAts[offset];
            offset++;
            printf("    * Specifics (Virtual Card Selection):\n");
            if ((VCS & 0x09) == 0x00) {
              printf("      * Only VCSL supported\n");
            } else if ((VCS & 0x09) == 0x01) {
              printf("      * VCS, VCSL and SVC supported\n");
            }
            if ((VCS & 0x0e) == 0x00) {
              printf("      * SL1, SL2(?), SL3 supported\n");
            } else if ((VCS & 0x0e) == 0x02) {
              printf("      * SL3 only card\n");
            } else if ((VCS & 0x0f) == 0x0e) {
              printf("      * No VCS command supported\n");
            } else if ((VCS & 0x0f) == 0x0f) {
              printf("      * Unspecified\n");
            } else {
              printf("      * RFU\n");
            }
          }
        }
      } else {
        if (CIB == 0x00) {
          printf("  * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n");
          printf("    followed by a mandatory status indicator (the last three bytes, not in TLV)\n");
          printf("    See ISO/IEC 7816-4 8.1.1.3 for more info\n");
        }
        if (CIB == 0x10) {
          printf("  * DIR data reference: %02x\n", nai.abtAts[offset]);
        }
        if (CIB == 0x80) {
          if (nai.szAtsLen == offset) {
            printf("  * No COMPACT-TLV objects found, no status found\n");
          } else {
            printf("  * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n");
            printf("    the last data object may carry a status indicator of one, two or three bytes.\n");
            printf("    See ISO/IEC 7816-4 8.1.1.3 for more info\n");
          }
        }
      }
    }
  }
  if (verbose) {
    printf("\nFingerprinting based on MIFARE type Identification Procedure:\n"); // AN10833
    uint16_t atqa = 0;
    uint8_t sak = 0;
    uint8_t i, j;
    bool found_possible_match = false;

    atqa = (((uint16_t)nai.abtAtqa[0] & 0xff)<<8);
    atqa += (((uint16_t)nai.abtAtqa[1] & 0xff));
    sak = ((uint8_t)nai.btSak & 0xff);

    for (i = 0; i < sizeof(const_ca)/sizeof(const_ca[0]); i++) {
      if ((atqa & const_ca[i].mask) == const_ca[i].atqa) {
        for (j = 0; (j < sizeof(const_ca[i].saklist)) && (const_ca[i].saklist[j] >= 0); j++) {
          int sakindex = const_ca[i].saklist[j];
          if ((sak & const_cs[sakindex].mask) == const_cs[sakindex].sak) {
            printf("* %s%s\n", const_ca[i].type, const_cs[sakindex].type);
            found_possible_match = true;
          }
        }
      }
    }
    // Other matches not described in
    // AN10833 MIFARE Type Identification Procedure
    // but seen in the field:
    printf("Other possible matches based on ATQA & SAK values:\n");
    uint32_t atqasak = 0;
    atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff)<<16);
    atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff)<<8);
    atqasak += ((uint32_t)nai.btSak & 0xff);
    switch (atqasak) {
      case 0x000488:
        printf("* Mifare Classic 1K Infineon\n");
        found_possible_match = true;
      break;
      case 0x000298:
        printf("* Gemplus MPCOS\n");
        found_possible_match = true;
      break;
      case 0x030428:
        printf("* JCOP31\n");
        found_possible_match = true;
      break;
      case 0x004820:
        printf("* JCOP31 v2.4.1\n");
        printf("* JCOP31 v2.2\n");
        found_possible_match = true;
      break;
      case 0x000428:
        printf("* JCOP31 v2.3.1\n");
        found_possible_match = true;
      break;
      case 0x000453:
        printf("* Fudan FM1208SH01\n");
        found_possible_match = true;
      break;
      case 0x000820:
        printf("* Fudan FM1208\n");
        found_possible_match = true;
      break;
      case 0x000238:
        printf("* MFC 4K emulated by Nokia 6212 Classic\n");
        found_possible_match = true;
      break;
      case 0x000838:
        printf("* MFC 4K emulated by Nokia 6131 NFC\n");
        found_possible_match = true;
      break;
    }
    if (! found_possible_match) {
      printf("* Unknown card, sorry\n");
    }
  }
}

void
print_nfc_felica_info (const nfc_felica_info nfi, bool verbose)
{
  (void) verbose;
  printf ("        ID (NFCID2): ");
  print_hex (nfi.abtId, 8);
  printf ("    Parameter (PAD): ");
  print_hex (nfi.abtPad, 8);
  printf ("   System Code (SC): ");
  print_hex (nfi.abtSysCode, 2);
}

void
print_nfc_jewel_info (const nfc_jewel_info nji, bool verbose)
{
  (void) verbose;
  printf ("    ATQA (SENS_RES): ");
  print_hex (nji.btSensRes, 2);
  printf ("      4-LSB JEWELID: ");
  print_hex (nji.btId, 4);
}

#define PI_ISO14443_4_SUPPORTED 0x01
#define PI_NAD_SUPPORTED        0x01
#define PI_CID_SUPPORTED        0x02
void
print_nfc_iso14443b_info (const nfc_iso14443b_info nbi, bool verbose)
{
  const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
  printf ("               PUPI: ");
  print_hex (nbi.abtPupi, 4);
  printf ("   Application Data: ");
  print_hex (nbi.abtApplicationData, 4);
  printf ("      Protocol Info: ");
  print_hex (nbi.abtProtocolInfo, 3);
  if (verbose) {
    printf ("* Bit Rate Capability:\n");
    if (nbi.abtProtocolInfo[0] == 0) {
      printf (" * PICC supports only 106 kbits/s in both directions\n");
    }
    if (nbi.abtProtocolInfo[0] & 1<<7) {
      printf (" * Same bitrate in both directions mandatory\n");
    }
    if (nbi.abtProtocolInfo[0] & 1<<4) {
      printf (" * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n");
    }
    if (nbi.abtProtocolInfo[0] & 1<<5) {
      printf (" * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n");
    }
    if (nbi.abtProtocolInfo[0] & 1<<6) {
      printf (" * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n");
    }
    if (nbi.abtProtocolInfo[0] & 1<<0) {
      printf (" * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n");
    }
    if (nbi.abtProtocolInfo[0] & 1<<1) {
      printf (" * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n");
    }
    if (nbi.abtProtocolInfo[0] & 1<<2) {
      printf (" * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n");
    }
    if (nbi.abtProtocolInfo[0] & 1<<3) {
      printf (" * ERROR unknown value\n");
    }
    if( (nbi.abtProtocolInfo[1] & 0xf0) <= 0x80 ) {
      printf ("* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((nbi.abtProtocolInfo[1] & 0xf0) >> 4)]);
    }
    if((nbi.abtProtocolInfo[1] & 0x0f) == PI_ISO14443_4_SUPPORTED) {
      printf ("* Protocol types supported: ISO/IEC 14443-4\n");
    }
    printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((nbi.abtProtocolInfo[2] & 0xf0) >> 4))/13560.0);
    if((nbi.abtProtocolInfo[2] & (PI_NAD_SUPPORTED|PI_CID_SUPPORTED)) != 0) {
      printf ("* Frame options supported: ");
      if ((nbi.abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) printf ("NAD ");
      if ((nbi.abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) printf ("CID ");
      printf("\n");
    }
  }
}

void
print_nfc_iso14443bi_info (const nfc_iso14443bi_info nii, bool verbose)
{
  printf ("                DIV: ");
  print_hex (nii.abtDIV, 4);
  if (verbose) {
    int version = (nii.btVerLog & 0x1e)>>1;
    printf ("   Software Version: ");
    if (version == 15) {
      printf ("Undefined\n");
    } else {
      printf ("%i\n", version);
    }

    if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x80)){
      printf ("        Wait Enable: yes");
    }
  }
  if ((nii.btVerLog & 0x80) && (nii.btConfig & 0x40)) {
    printf ("                ATS: ");
    print_hex (nii.abtAtr, nii.szAtrLen);
  }
}

void
print_nfc_iso14443b2sr_info (const nfc_iso14443b2sr_info nsi, bool verbose)
{
  (void) verbose;
  printf ("                UID: ");
  print_hex (nsi.abtUID, 8);
}

void
print_nfc_iso14443b2ct_info (const nfc_iso14443b2ct_info nci, bool verbose)
{
  (void) verbose;
  uint32_t uid;
  uid = (nci.abtUID[3] << 24) + (nci.abtUID[2] << 16) + (nci.abtUID[1] << 8) + nci.abtUID[0];
  printf ("                UID: ");
  print_hex (nci.abtUID, sizeof(nci.abtUID));
  printf ("      UID (decimal): %010u\n", uid);
  printf ("       Product Code: %02X\n", nci.btProdCode);
  printf ("           Fab Code: %02X\n", nci.btFabCode);
}

void
print_nfc_dep_info (const nfc_dep_info ndi, bool verbose)
{
  (void) verbose;
  printf ("       NFCID3: ");
  print_hex (ndi.abtNFCID3, 10);
  printf ("           BS: %02x\n", ndi.btBS);
  printf ("           BR: %02x\n", ndi.btBR);
  printf ("           TO: %02x\n", ndi.btTO);
  printf ("           PP: %02x\n", ndi.btPP);
  if (ndi.szGB) {
    printf ("General Bytes: ");
    print_hex (ndi.abtGB, ndi.szGB);
  }
}

const char *
str_nfc_baud_rate (const nfc_baud_rate nbr)
{
  switch(nbr) {
    case NBR_UNDEFINED:
      return "undefined baud rate";
    break;
    case NBR_106:
      return "106 kbps";
    break;
    case NBR_212:
      return "212 kbps";
    break;
    case NBR_424:
      return "424 kbps";
    break;
    case NBR_847:
      return "847 kbps";
    break;
  }
  return "";
}

void
print_nfc_target (const nfc_target nt, bool verbose)
{
  switch(nt.nm.nmt) {
    case NMT_ISO14443A:
      printf ("ISO/IEC 14443A (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
      print_nfc_iso14443a_info (nt.nti.nai, verbose);
    break;
    case NMT_JEWEL:
      printf ("Innovision Jewel (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
      print_nfc_jewel_info (nt.nti.nji, verbose);
    break;
    case NMT_FELICA:
      printf ("FeliCa (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
      print_nfc_felica_info (nt.nti.nfi, verbose);
    break;
    case NMT_ISO14443B:
      printf ("ISO/IEC 14443-4B (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
      print_nfc_iso14443b_info (nt.nti.nbi, verbose);
    break;
    case NMT_ISO14443BI:
      printf ("ISO/IEC 14443-4B' (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
      print_nfc_iso14443bi_info (nt.nti.nii, verbose);
    break;
    case NMT_ISO14443B2SR:
      printf ("ISO/IEC 14443-2B ST SRx (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
      print_nfc_iso14443b2sr_info (nt.nti.nsi, verbose);
    break;
    case NMT_ISO14443B2CT:
      printf ("ISO/IEC 14443-2B ASK CTx (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
      print_nfc_iso14443b2ct_info (nt.nti.nci, verbose);
    break;
    case NMT_DEP:
      printf ("D.E.P. (%s, %s) target:\n", str_nfc_baud_rate(nt.nm.nbr), (nt.nti.ndi.ndm == NDM_ACTIVE)? "active mode" : "passive mode");
      print_nfc_dep_info (nt.nti.ndi, verbose);
    break;
  }
}