+               PrintAndLogEx(NORMAL, "      BCC1 : %02X, crc should be %02X", data[8], crc1 );
+
+       PrintAndLogEx(NORMAL, "  Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " );
+
+       PrintAndLogEx(NORMAL, "      Lock : %s       (binary %s %s)",
+                               sprint_hex(data+10, 2),
+                               printBits(1, data+10),
+                               printBits(1, data+11)
+               );
+
+       PrintAndLogEx(NORMAL, "OneTimePad : %s (binary %s %s %s %s)\n",
+                               sprint_hex(data+12, 4),
+                               printBits(1, data+12),
+                               printBits(1, data+13),
+                               printBits(1, data+14),
+                               printBits(1, data+15)
+               );
+
+       return 0;
+}
+
+
+static int ndef_print_CC(uint8_t *data) {
+       // no NDEF message
+       if(data[0] != 0xe1)
+               return -1;
+
+       PrintAndLogEx(NORMAL, "--- NDEF Message");
+       PrintAndLogEx(NORMAL, "Capability Container: %s", sprint_hex(data,4) );
+       PrintAndLogEx(NORMAL, "  %02X : NDEF Magic Number", data[0]);
+       PrintAndLogEx(NORMAL, "  %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f);
+       PrintAndLogEx(NORMAL, "  %02X : Physical Memory Size: %d bytes", data[2], (data[2] + 1) * 8);
+       if ( data[2] == 0x12 )
+               PrintAndLogEx(NORMAL, "  %02X : NDEF Memory Size: %d bytes", data[2], 144);
+       else if ( data[2] == 0x3e )
+               PrintAndLogEx(NORMAL, "  %02X : NDEF Memory Size: %d bytes", data[2], 496);
+       else if ( data[2] == 0x6d )
+               PrintAndLogEx(NORMAL, "  %02X : NDEF Memory Size: %d bytes", data[2], 872);
+
+       PrintAndLogEx(NORMAL, "  %02X : %s / %s", data[3],
+                               (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security",
+                               (data[3] & 0x0F)==0 ? "Write access granted without any security" : (data[3] & 0x0F)==0x0F ? "No write access granted at all" : "(RFU)");
+       return 0;
+}
+
+
+int ul_print_type(uint32_t tagtype, uint8_t spaces){
+       char spc[11] = "          ";
+       spc[10]=0x00;
+       char *spacer = spc + (10-spaces);
+
+       if (tagtype & UL )
+               PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "<magic>" : "" );
+       else if (tagtype & UL_C)
+               PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "<magic>" : "" );
+       else if (tagtype & UL_EV1_48)
+               PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer);
+       else if (tagtype & UL_EV1_128)
+               PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer);
+       else if (tagtype & NTAG)
+               PrintAndLogEx(NORMAL, "%sTYPE : NTAG UNKNOWN", spacer);
+       else if (tagtype & NTAG_203)
+               PrintAndLogEx(NORMAL, "%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer);
+       else if (tagtype & NTAG_210)
+               PrintAndLogEx(NORMAL, "%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer);
+       else if (tagtype & NTAG_212)
+               PrintAndLogEx(NORMAL, "%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer);
+       else if (tagtype & NTAG_213)
+               PrintAndLogEx(NORMAL, "%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer);
+       else if (tagtype & NTAG_215)
+               PrintAndLogEx(NORMAL, "%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer);
+       else if (tagtype & NTAG_216)
+               PrintAndLogEx(NORMAL, "%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer);
+       else if (tagtype & NTAG_I2C_1K)
+               PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD");
+       else if (tagtype & NTAG_I2C_2K)
+               PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD");
+       else if (tagtype & MY_D)
+               PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer);
+       else if (tagtype & MY_D_NFC)
+               PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer);
+       else if (tagtype & MY_D_MOVE)
+               PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move | my-d\x99move NFC (SLE 66R01P)", spacer);
+       else if (tagtype & MY_D_MOVE_LEAN)
+               PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer);
+       else if (tagtype & FUDAN_UL)
+               PrintAndLogEx(NORMAL, "%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "<magic>" : "" );
+       else
+               PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype);
+       return 0;
+}
+
+
+static int ulc_print_3deskey(uint8_t *data) {
+       PrintAndLogEx(NORMAL, "         deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data   ,4),data);
+       PrintAndLogEx(NORMAL, "         deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4);
+       PrintAndLogEx(NORMAL, "         deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8);
+       PrintAndLogEx(NORMAL, "         deskey2 [47/0x2F] : %s [%.4s]", sprint_hex(data+12,4),data+12);
+       PrintAndLogEx(NORMAL, "\n 3des key : %s", sprint_hex(SwapEndian64(data, 16, 8), 16));
+       return 0;
+}
+
+
+static int ulc_print_configuration(uint8_t *data) {
+
+       PrintAndLogEx(NORMAL, "--- UL-C Configuration");
+       PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s       (binary %s %s)",
+               sprint_hex(data, 2),
+               printBits(1, data),
+               printBits(1, data+1)
+               );
+       PrintAndLogEx(NORMAL, "         Counter [41/0x29] : %s", sprint_hex(data+4, 2));
+
+       bool validAuth = (data[8] >= 0x03 && data[8] <= 0x30);
+       if (validAuth)
+               PrintAndLogEx(NORMAL, "           Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8], data[8] );
+       else{
+               if (data[8] == 0) {
+                       PrintAndLogEx(NORMAL, "           Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) );
+               } else {
+                       PrintAndLogEx(NORMAL, "           Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) );
+               }
+       }
+       PrintAndLogEx(NORMAL, "           Auth1 [43/0x2B] : %s %s",
+                       sprint_hex(data+12, 4),
+                       (data[12] & 1) ? "write access restricted": "read and write access restricted"
+                       );
+       return 0;
+}
+
+
+static int ulev1_print_configuration(uint8_t *data, uint8_t startPage) {
+
+       PrintAndLogEx(NORMAL, "\n--- Tag Configuration");
+
+       bool strg_mod_en = (data[0] & 2);
+       uint8_t authlim = (data[4] & 0x07);
+       bool cfglck = (data[4] & 0x40);
+       bool prot = (data[4] & 0x80);
+       uint8_t vctid = data[5];
+
+       PrintAndLogEx(NORMAL, "  cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4));
+       if (data[3] < 0xff)
+               PrintAndLogEx(NORMAL, "                    - page %d and above need authentication", data[3]);
+       else
+               PrintAndLogEx(NORMAL, "                    - pages don't need authentication");
+       PrintAndLogEx(NORMAL, "                    - strong modulation mode %s", (strg_mod_en) ? "enabled" : "disabled");
+       PrintAndLogEx(NORMAL, "  cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1,  sprint_hex(data+4, 4) );
+       if (authlim == 0)
+               PrintAndLogEx(NORMAL, "                    - Unlimited password attempts");
+       else
+               PrintAndLogEx(NORMAL, "                    - Max number of password attempts is %d", authlim);
+       PrintAndLogEx(NORMAL, "                    - user configuration %s", cfglck ? "permanently locked":"writeable");
+       PrintAndLogEx(NORMAL, "                    - %s access is protected with password", prot ? "read and write":"write");
+       PrintAndLogEx(NORMAL, "                    - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not");
+       PrintAndLogEx(NORMAL, "  PWD  [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4));
+       PrintAndLogEx(NORMAL, "  PACK [%u/0x%02X] : %s      - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2));
+       PrintAndLogEx(NORMAL, "  RFU  [%u/0x%02X] :       %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2));
+       return 0;
+}
+
+
+static int ulev1_print_counters(void) {
+       PrintAndLogEx(NORMAL, "--- Tag Counters");
+       uint8_t tear[1] = {0};
+       uint8_t counter[3] = {0,0,0};
+       uint16_t len = 0;
+       for ( uint8_t i = 0; i<3; ++i) {
+               ulev1_readTearing(i, tear, sizeof(tear));
+               len = ulev1_readCounter(i, counter, sizeof(counter) );
+               if (len == 3) {
+                       PrintAndLogEx(NORMAL, "       [%0d] : %s", i, sprint_hex(counter,3));
+                       PrintAndLogEx(NORMAL, "                    - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure");
+               }
+       }
+       return len;
+}
+
+
+static int ulev1_print_signature( uint8_t *data, uint8_t len){
+       PrintAndLogEx(NORMAL, "\n--- Tag Signature");
+       PrintAndLogEx(NORMAL, "IC signature public key name  : NXP NTAG21x (2013)");
+       PrintAndLogEx(NORMAL, "IC signature public key value : %s", sprint_hex(public_ecda_key, PUBLIC_ECDA_KEYLEN));
+       PrintAndLogEx(NORMAL, "    Elliptic curve parameters : secp128r1");
+       PrintAndLogEx(NORMAL, "            Tag ECC Signature : %s", sprint_hex(data, len));
+       //to do:  verify if signature is valid
+       //PrintAndLogEx(NORMAL, "IC signature status: %s valid", (iseccvalid() )?"":"not");
+       return 0;
+}
+
+
+static int ulev1_print_version(uint8_t *data){
+       PrintAndLogEx(NORMAL, "\n--- Tag Version");
+       PrintAndLogEx(NORMAL, "       Raw bytes : %s", sprint_hex(data, 8) );
+       PrintAndLogEx(NORMAL, "       Vendor ID : %02X, %s", data[1], getManufacturerName(data[1]));
+       PrintAndLogEx(NORMAL, "    Product type : %s", getProductTypeStr(data[2]));
+       PrintAndLogEx(NORMAL, " Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF");
+       PrintAndLogEx(NORMAL, "   Major version : %02X", data[4]);
+       PrintAndLogEx(NORMAL, "   Minor version : %02X", data[5]);
+       PrintAndLogEx(NORMAL, "            Size : %s", getUlev1CardSizeStr(data[6]));
+       PrintAndLogEx(NORMAL, "   Protocol type : %02X", data[7]);
+       return 0;
+}
+
+
+static int ul_magic_test(void) {
+       // try a compatibility write to page0, and see if tag answers with ACK/NACK to the first part of the command
+       iso14a_card_select_t card;
+       if (!ul_select(&card, false))
+               return UL_ERROR;
+       int status = ul_comp_write_ex(0, NULL, 0, true);
+       if (status == 0) {
+               return MAGIC;
+       }
+       return 0;
+}
+
+
+uint32_t GetHF14AMfU_Type(void){
+
+       TagTypeUL_t tagtype = UNKNOWN;
+       iso14a_card_select_t card;
+       uint8_t version[10] = {0x00};
+       int len;
+
+       if (!ul_select(&card, true)) {
+               DropField();
+               msleep(200);
+               return UL_ERROR;
+       }
+
+       // Check for Ultralight Family
+       if (card.uidlen != 7 || (card.sak & 0x38) != 0x00) {
+               DropField();
+               PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D  [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak);
+               return UL_ERROR;
+       }
+
+       if (card.uid[0] != 0x05) {
+               len  = ulev1_getVersion(version, sizeof(version));
+               if (len == 10) {
+                       if (version[2] == 0x03 && version[6] == 0x0B)
+                               tagtype = UL_EV1_48;
+                       else if (version[2] == 0x03 && version[6] != 0x0B)
+                               tagtype = UL_EV1_128;
+                       else if (version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0B)
+                               tagtype = NTAG_210;
+                       else if (version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0E)
+                               tagtype = NTAG_212;
+                       else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x0F)
+                               tagtype = NTAG_213;
+                       else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x11)
+                               tagtype = NTAG_215;
+                       else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x13)
+                               tagtype = NTAG_216;
+                       else if (version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x13)
+                               tagtype = NTAG_I2C_1K;
+                       else if (version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x15)
+                               tagtype = NTAG_I2C_2K;
+                       else if (version[2] == 0x04)
+                               tagtype = NTAG;
+               }
+
+               // UL vs UL-C vs ntag203 test
+               if (tagtype == UNKNOWN) {
+                       ul_halt();
+                       if (!ul_select(&card, false)) {
+                               DropField();
+                               msleep(200);
+                               return UL_ERROR;
+                       }
+
+                       // do UL_C check first...
+                       uint8_t nonce[11] = {0x00};
+                       len = ulc_requestAuthentication(nonce, sizeof(nonce));
+                       ul_halt();
+                       if (len == 11) {
+                               tagtype = UL_C;
+                       } else {
+                               // need to re-select after authentication error
+                               if (!ul_select(&card, false)) {
+                                       DropField();
+                                       msleep(200);
+                                       return UL_ERROR;
+                               }
+
+                               uint8_t data[16] = {0x00};
+                               // read page 0x29 (last valid ntag203 page)
+                               len = ul_read(0x29, data, sizeof(data));
+                               if (len <= 1) {
+                                       tagtype = UL;
+                               } else {
+                                       // read page 0x30 (should error if it is a ntag203)
+                                       len = ul_read(0x30, data, sizeof(data));
+                                       if (len <= 1) {
+                                               ul_halt();
+                                               tagtype = NTAG_203;
+                                       }
+                               }
+                       }
+               }
+               if (tagtype & UL) {
+                       tagtype = ul_fudan_check();
+                       ul_halt();
+               }
+
+       } else {  // manufacturer Infineon. Check for my-d variants
+
+               uint8_t nib = (card.uid[1] & 0xf0) >> 4;
+               switch (nib) {
+                       case 1: tagtype = MY_D; break;                      //or SLE 66RxxS ... up to 512 pages of 8 user bytes...
+                       case 2: tagtype = MY_D_NFC; break;                  //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes)
+                       case 3: tagtype = MY_D_MOVE; break;                 //or SLE 66R01P  // 38 pages of 4 bytes
+                       case 7: tagtype = MY_D_MOVE_LEAN; break;            //or SLE 66R01L  // 16 pages of 4 bytes
+               }
+       }
+
+       tagtype |= ul_magic_test();