From 1353ba6dfcf778339e99f2e54e7f2a6f59b39dec Mon Sep 17 00:00:00 2001 From: whywilson Date: Thu, 26 Dec 2024 17:22:07 +0800 Subject: [PATCH] Add Mifare Ultralight Tag read and write with PN532 BLE. --- src/modules/rfid/pn532ble.cpp | 345 +++++++++++++++++++++++++++++++--- src/modules/rfid/pn532ble.h | 2 + 2 files changed, 323 insertions(+), 24 deletions(-) diff --git a/src/modules/rfid/pn532ble.cpp b/src/modules/rfid/pn532ble.cpp index 55041c26..0ca05e2b 100644 --- a/src/modules/rfid/pn532ble.cpp +++ b/src/modules/rfid/pn532ble.cpp @@ -65,6 +65,48 @@ void Pn532ble::loop() { selectMode(); } + +#ifdef CARDPUTER + if (pn532_ble.isConnected()) + { + if (checkLetterShortcutPress() == 'h') + { + setMode(HF_14A_SCAN_MODE); + } + + if (checkLetterShortcutPress() == 'v') + { + setMode(GET_FW_MODE); + } + + if (checkLetterShortcutPress() == 'c') + { + setMode(HF_MF_READ_MODE); + } + + if (checkLetterShortcutPress() == 'u') + { + setMode(HF_MFU_READ_MODE); + } + } + + if (pn532_ble.isPN532Killer()) + { + if (checkLetterShortcutPress() == 'H') + { + setMode(HF_15_SCAN_MODE); + } + + if (checkLetterShortcutPress() == 'l') + { + setMode(LF_EM4100_SCAN_MODE); + } + if (checkLetterShortcutPress() == 'i') + { + setMode(HF_ISO15693_READ_MODE); + } + } +#endif } } @@ -122,8 +164,8 @@ void Pn532ble::readTagMenu() options = { {"Read MFC", [=]() { setMode(HF_MF_READ_MODE); }}, - // {"Read MFU", [=]() - // { setMode(HF_MFU_READ_MODE); }}, + {"Read MFU", [=]() + { setMode(HF_MFU_READ_MODE); }}, }; if (pn532_ble.isPN532Killer()) @@ -253,9 +295,28 @@ void Pn532ble::setMode(AppMode mode) { case STANDBY_MODE: padprintln(""); - padprintln("Press [OK] to change mode."); - padprintln(""); + padprintln("[ok] - Select mode"); +#ifdef CARDPUTER + if (pn532_ble.isConnected()) + { + padprintln("[h] - Scan ISO14443A"); + } + if (pn532_ble.isPN532Killer()) + { + padprintln("[H] - Scan ISO15693"); + padprintln("[l] - Scan EM4100"); + } padprintln(""); + if (pn532_ble.isConnected()) + { + padprintln("[c] - Read Mifare Classic"); + padprintln("[u] - Read Mifare Ultralight"); + } + if (pn532_ble.isPN532Killer()) + { + padprintln("[i] - Read ISO15693"); + } +#endif break; case GET_FW_MODE: if (pn532_ble.isConnected()) @@ -280,7 +341,7 @@ void Pn532ble::setMode(AppMode mode) hf14aMfReadDumpMode(); break; case HF_MFU_READ_MODE: - + hf14aMfuReadDumpMode(); break; case HF_ISO15693_READ_MODE: hf15ReadDumpMode(); @@ -289,7 +350,7 @@ void Pn532ble::setMode(AppMode mode) hf14aMfWriteDumpMode(); break; case HF_MFU_WRITE_MODE: - + hf14aMfuWriteDumpMode(); break; case HF_ISO15693_WRITE_MODE: hf15WriteDumpMode(); @@ -310,7 +371,7 @@ void Pn532ble::displayBanner() { drawMainBorderWithTitle("PN532 BLE"); padprintln("PN532 HSU Mode on BLE"); - delay(300); + delay(100); } void Pn532ble::showDeviceInfo() @@ -336,7 +397,7 @@ void Pn532ble::showDeviceInfo() padprintln(versionStr); padprintln("------------"); padprintln(""); - padprintln("Press OK to select mode."); + padprintln("[ok] - Select mode"); } void Pn532ble::hf14aScan() @@ -350,6 +411,10 @@ void Pn532ble::hf14aScan() { displayError("No tag found"); } + else if (tagInfo.uid.size() != 4 && tagInfo.uid.size() != 7 && tagInfo.uid.size() != 10) + { + displayError("Not ISO14443A Tag"); + } else { padprintln("------------"); @@ -357,12 +422,19 @@ void Pn532ble::hf14aScan() padprintln("UID: " + tagInfo.uid_hex); padprintln("ATQA: " + tagInfo.atqa_hex); padprintln("SAK: " + tagInfo.sak_hex); - bool isGen1A = pn532_ble.isGen1A(); - padprintln("Gen1A: " + String(isGen1A ? "Yes" : "No")); - bool isGen3 = pn532_ble.isGen3(); - padprintln("Gen3: " + String(isGen3 ? "Yes" : "No")); - bool isGen4 = pn532_ble.isGen4(gen4pwd); - padprintln("Gen4: " + String(isGen4 ? "Yes" : "No")); + if (tagInfo.sak == 0x00) + { + padprintln("------------"); + } + else if (tagInfo.sak == 0x08 || tagInfo.sak == 0x09 || tagInfo.sak == 0x18) + { + bool isGen1A = pn532_ble.isGen1A(); + padprintln("Gen1A: " + String(isGen1A ? "Yes" : "No")); + bool isGen3 = pn532_ble.isGen3(); + padprintln("Gen3: " + String(isGen3 ? "Yes" : "No")); + bool isGen4 = pn532_ble.isGen4(gen4pwd); + padprintln("Gen4: " + String(isGen4 ? "Yes" : "No")); + } } } @@ -371,12 +443,21 @@ void Pn532ble::hf15Scan() displayBanner(); padprintln("HF 15 Scan"); delay(200); + if (!pn532_ble.isPN532Killer()) + { + displayError("Not supported"); + return; + } pn532_ble.setNormalMode(); PN532_BLE::Iso15TagInfo tagInfo = pn532_ble.hf15Scan(); if (tagInfo.uid.empty()) { displayError("No tag found"); } + else if (tagInfo.uid.size() != 8) + { + displayError("Not ISO15693 Tag"); + } else { padprintln("------------"); @@ -394,6 +475,12 @@ void Pn532ble::lfScan() displayBanner(); padprintln("LF Scan"); delay(200); + if (!pn532_ble.isPN532Killer()) + { + displayError("Not supported"); + return; + } + pn532_ble.setNormalMode(); PN532_BLE::LfTagInfo tagInfo = pn532_ble.lfScan(); if (tagInfo.uid.empty()) @@ -404,7 +491,7 @@ void Pn532ble::lfScan() { padprintln("------------"); padprintln("UID: " + tagInfo.uid_hex); - padprintln("ID: " + String(abs(tagInfo.id_dec))); + padprintln("ID: " + String(abs(tagInfo.id_dec))); } } @@ -424,10 +511,10 @@ void updateArea(ScrollableTextArea &area) void Pn532ble::hf14aMfReadDumpMode() { displayBanner(); - padprintln("HF 14A Dump"); + padprintln("HF MFC Dump"); + padprintln("------------"); pn532_ble.setNormalMode(); PN532_BLE::Iso14aTagInfo tagInfo = pn532_ble.hf14aScan(); - padprintln("------------"); if (tagInfo.uid.empty()) { displayError("No tag found"); @@ -624,20 +711,230 @@ void Pn532ble::hf14aMfReadDumpMode() area.draw(); } pn532_ble.wakeup(); + + while (checkSelPress()) + { + updateArea(area); + yield(); + } + while (!checkSelPress()) + { + updateArea(area); + yield(); + } } + else + { + area.addLine("Not Mifare Ultralight"); + area.scrollDown(); + area.draw(); + } +} - while (checkSelPress()) +void Pn532ble::hf14aMfuReadDumpMode() +{ + displayBanner(); + padprintln("HF MFU Dump"); + padprintln("------------"); + pn532_ble.setNormalMode(); + PN532_BLE::Iso14aTagInfo tagInfo = pn532_ble.hf14aScan(); + if (tagInfo.uid.empty()) { - updateArea(area); - yield(); + displayError("No tag found"); + return; } - while (!checkSelPress()) + mfd.clear(); + padprintln("UID: " + tagInfo.uid_hex); + + ScrollableTextArea area(FP, 10, 28, WIDTH - 20, HEIGHT - 38); + + if (tagInfo.sak == 0x00) { - updateArea(area); - yield(); + mfud.clear(); + padprintln("TYPE: " + tagInfo.type); + padprintln("------------"); + padprintln("Checking Page Count..."); + delay(1000); + area.addLine("TYPE: " + tagInfo.type); + area.scrollDown(); + area.draw(); + area.addLine("UID: " + tagInfo.uid_hex); + area.scrollDown(); + area.draw(); + + int max_block = 4; + int block = 0; + while (block < max_block) + { + std::vector res = pn532_ble.mfRdbl(block); + if (res.size() == 17) + { + res.erase(res.begin()); + } + if (block == 0 && res.size() == 16) + { + max_block = res[14] * 2 + 9; + area.addLine("PAGE: " + String(max_block)); + area.addLine("------------"); + area.scrollDown(); + area.draw(); + } + if (res.size() == 16) + { + for (int i = 0; i < 4; i++) + { + int block_index = block + i; + String blockStr = String(block_index < 10 ? "0" : "") + String(block_index) + " "; + for (int k = 0; k < 4; k++) + { + uint8_t byteData = res[i * 4 + k]; + mfud.push_back(byteData); + blockStr += byteData < 0x10 ? "0" : ""; + blockStr += String(byteData, HEX); + } + blockStr += " | "; + if (block_index == 0) + { + blockStr += "ID 0-2, BCC1"; + } + else if (block_index == 1) + { + blockStr += "ID 3-6"; + } + else if (block_index == 2) + { + blockStr += "BCC2,"; + } + else + { + for (int k = 0; k < 4; k++) + { + uint8_t byteData = res[i * 4 + k]; + if (byteData >= 32 && byteData <= 126) + { + blockStr += char(byteData); + } + else + { + blockStr += " "; + } + } + } + + area.addLine(blockStr); + area.scrollDown(); + area.draw(); + } + } + else + { + padprintln("Block " + String(block) + " Failed to read"); + } + block += 4; + } + area.addLine("------------"); + area.scrollDown(); + area.draw(); + pn532_ble.wakeup(); + + while (checkSelPress()) + { + updateArea(area); + yield(); + } + while (!checkSelPress()) + { + updateArea(area); + yield(); + } + } + else + { + area.addLine("Not Mifare Ultralight"); + area.scrollDown(); + area.draw(); } } +void Pn532ble::hf14aMfuWriteDumpMode() +{ + displayBanner(); + padprintln("HF MFU Write Dump"); + pn532_ble.setNormalMode(); + PN532_BLE::Iso14aTagInfo tagInfo = pn532_ble.hf14aScan(); + padprintln("------------"); + if (tagInfo.uid.empty()) + { + displayError("No tag found"); + return; + } + padprintln("UID: " + tagInfo.uid_hex); + + ScrollableTextArea area(FP, 10, 28, WIDTH - 20, HEIGHT - 38); + + padprintln("Type: " + tagInfo.type); + if (tagInfo.sak == 0x00) + { + area.addLine("Write Mifare Ultralight"); + area.addLine("------------"); + area.scrollDown(); + area.draw(); + delay(200); + int max_block = 4; + int block = 0; + std::vector first4Page = pn532_ble.mfRdbl(block); + if (first4Page.size() == 17) + { + first4Page.erase(first4Page.begin()); + } + if (first4Page.size() == 16) + { + max_block = first4Page[14] * 2 + 9; + } + + if (max_block > mfud.size() / 4) + { + displayError("Dump size not enough"); + return; + } + + for (int i = 0; i < mfud.size(); i += 4) + { + std::vector data(mfud.begin() + i, mfud.begin() + i + 4); + bool res = pn532_ble.mfuWrbl(block, data); + if (res) + { + area.addLine("Block " + String(block) + " write success"); + } + else + { + area.addLine("Block " + String(block) + " write failed"); + } + area.scrollDown(); + area.draw(); + block += 4; + } + area.addLine("------------"); + area.scrollDown(); + area.draw(); + + pn532_ble.wakeup(); + while (checkSelPress()) + { + updateArea(area); + yield(); + } + while (!checkSelPress()) + { + updateArea(area); + yield(); + } + }else{ + area.addLine("Not Mifare Ultralight"); + area.scrollDown(); + area.draw(); + } +} void Pn532ble::hf14aMfWriteDumpMode() { displayBanner(); @@ -657,7 +954,7 @@ void Pn532ble::hf14aMfWriteDumpMode() padprintln("Type: " + tagInfo.type); if (mfd.size() == 1024 && pn532_ble.isGen1A()) { - area.addLine("Write Dump to Gen1A"); + area.addLine("Write Mifare Classic"); area.addLine("------------"); area.scrollDown(); area.draw(); diff --git a/src/modules/rfid/pn532ble.h b/src/modules/rfid/pn532ble.h index e5735187..b89a6191 100644 --- a/src/modules/rfid/pn532ble.h +++ b/src/modules/rfid/pn532ble.h @@ -47,6 +47,8 @@ class Pn532ble void hf15Scan(); void lfScan(); void hf14aMfReadDumpMode(); + void hf14aMfuReadDumpMode(); + void hf14aMfuWriteDumpMode(); void hf14aMfWriteDumpMode(); void hf14aMfWriteDump(ScrollableTextArea &area); void hf15ReadDumpMode();