|
|
|
@@ -23,6 +23,7 @@ bool tagProcessed = false;
|
|
|
|
|
volatile bool pauseBambuMqttTask = false;
|
|
|
|
|
volatile bool nfcReadingTaskSuspendRequest = false;
|
|
|
|
|
volatile bool nfcReadingTaskSuspendState = false;
|
|
|
|
|
volatile bool nfcWriteInProgress = false; // Prevent any tag operations during write
|
|
|
|
|
|
|
|
|
|
struct NfcWriteParameterType {
|
|
|
|
|
bool tagType;
|
|
|
|
@@ -223,38 +224,6 @@ uint16_t getMaxUserDataPages()
|
|
|
|
|
return maxPages;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool clearUserDataArea() {
|
|
|
|
|
// IMPORTANT: Only clear user data pages, NOT configuration pages
|
|
|
|
|
// NTAG layout: Pages 0-3 (header), 4-N (user data), N+1-N+3 (config) - NEVER touch config!
|
|
|
|
|
String tagType = detectNtagType();
|
|
|
|
|
|
|
|
|
|
// Calculate safe user data page ranges (NEVER touch config pages!)
|
|
|
|
|
uint16_t firstUserPage = 4;
|
|
|
|
|
uint16_t lastUserPage = 0;
|
|
|
|
|
|
|
|
|
|
if (tagType == "NTAG213") {
|
|
|
|
|
lastUserPage = 39; // Pages 40-42 are config - DO NOT TOUCH!
|
|
|
|
|
Serial.println("NTAG213: Sichere Löschung Seiten 4-39");
|
|
|
|
|
} else if (tagType == "NTAG215") {
|
|
|
|
|
lastUserPage = 129; // Pages 130-132 are config - DO NOT TOUCH!
|
|
|
|
|
Serial.println("NTAG215: Sichere Löschung Seiten 4-129");
|
|
|
|
|
} else if (tagType == "NTAG216") {
|
|
|
|
|
lastUserPage = 225; // Pages 226-228 are config - DO NOT TOUCH!
|
|
|
|
|
Serial.println("NTAG216: Sichere Löschung Seiten 4-225");
|
|
|
|
|
} else {
|
|
|
|
|
// Conservative fallback - only clear a small safe area
|
|
|
|
|
lastUserPage = 39;
|
|
|
|
|
Serial.println("UNKNOWN TAG: Konservative Löschung Seiten 4-39");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.println("WARNUNG: Vollständiges Löschen kann Tag beschädigen!");
|
|
|
|
|
Serial.println("Verwende stattdessen selective NDEF-Überschreibung...");
|
|
|
|
|
|
|
|
|
|
// Instead of clearing everything, just write a minimal NDEF structure
|
|
|
|
|
// This is much safer and preserves tag integrity
|
|
|
|
|
return initializeNdefStructure();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool initializeNdefStructure() {
|
|
|
|
|
// Write minimal NDEF structure without destroying the tag
|
|
|
|
|
// This creates a clean slate while preserving tag functionality
|
|
|
|
@@ -300,6 +269,38 @@ bool initializeNdefStructure() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool clearUserDataArea() {
|
|
|
|
|
// IMPORTANT: Only clear user data pages, NOT configuration pages
|
|
|
|
|
// NTAG layout: Pages 0-3 (header), 4-N (user data), N+1-N+3 (config) - NEVER touch config!
|
|
|
|
|
String tagType = detectNtagType();
|
|
|
|
|
|
|
|
|
|
// Calculate safe user data page ranges (NEVER touch config pages!)
|
|
|
|
|
uint16_t firstUserPage = 4;
|
|
|
|
|
uint16_t lastUserPage = 0;
|
|
|
|
|
|
|
|
|
|
if (tagType == "NTAG213") {
|
|
|
|
|
lastUserPage = 39; // Pages 40-42 are config - DO NOT TOUCH!
|
|
|
|
|
Serial.println("NTAG213: Sichere Löschung Seiten 4-39");
|
|
|
|
|
} else if (tagType == "NTAG215") {
|
|
|
|
|
lastUserPage = 129; // Pages 130-132 are config - DO NOT TOUCH!
|
|
|
|
|
Serial.println("NTAG215: Sichere Löschung Seiten 4-129");
|
|
|
|
|
} else if (tagType == "NTAG216") {
|
|
|
|
|
lastUserPage = 225; // Pages 226-228 are config - DO NOT TOUCH!
|
|
|
|
|
Serial.println("NTAG216: Sichere Löschung Seiten 4-225");
|
|
|
|
|
} else {
|
|
|
|
|
// Conservative fallback - only clear a small safe area
|
|
|
|
|
lastUserPage = 39;
|
|
|
|
|
Serial.println("UNKNOWN TAG: Konservative Löschung Seiten 4-39");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.println("WARNUNG: Vollständiges Löschen kann Tag beschädigen!");
|
|
|
|
|
Serial.println("Verwende stattdessen selective NDEF-Überschreibung...");
|
|
|
|
|
|
|
|
|
|
// Instead of clearing everything, just write a minimal NDEF structure
|
|
|
|
|
// This is much safer and preserves tag integrity
|
|
|
|
|
return initializeNdefStructure();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
|
|
|
|
// Determine exact tag type and capabilities first
|
|
|
|
|
String tagType = detectNtagType();
|
|
|
|
@@ -314,6 +315,39 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
|
|
|
|
Serial.print("Max Writable Page: ");Serial.println(maxWritablePage);
|
|
|
|
|
Serial.println("========================");
|
|
|
|
|
|
|
|
|
|
// Perform additional tag validation by testing write boundaries
|
|
|
|
|
Serial.println("=== TAG VALIDATION ===");
|
|
|
|
|
uint8_t testBuffer[4] = {0x00, 0x00, 0x00, 0x00};
|
|
|
|
|
|
|
|
|
|
// Test if we can actually read the max page
|
|
|
|
|
if (!nfc.ntag2xx_ReadPage(maxWritablePage, testBuffer)) {
|
|
|
|
|
Serial.print("WARNING: Cannot read declared max page ");
|
|
|
|
|
Serial.println(maxWritablePage);
|
|
|
|
|
|
|
|
|
|
// Find actual maximum writable page by testing backwards
|
|
|
|
|
uint16_t actualMaxPage = maxWritablePage;
|
|
|
|
|
for (uint16_t testPage = maxWritablePage; testPage >= 4; testPage--) {
|
|
|
|
|
if (nfc.ntag2xx_ReadPage(testPage, testBuffer)) {
|
|
|
|
|
actualMaxPage = testPage;
|
|
|
|
|
Serial.print("Found actual max readable page: ");
|
|
|
|
|
Serial.println(actualMaxPage);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
maxWritablePage = actualMaxPage;
|
|
|
|
|
} else {
|
|
|
|
|
Serial.print("✓ Max page ");Serial.print(maxWritablePage);Serial.println(" is readable");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculate maximum available user data based on actual writable pages
|
|
|
|
|
uint16_t actualUserDataSize = (maxWritablePage - 3) * 4; // -3 because pages 0-3 are header
|
|
|
|
|
availableUserData = actualUserDataSize;
|
|
|
|
|
|
|
|
|
|
Serial.print("Actual available user data: ");
|
|
|
|
|
Serial.print(actualUserDataSize);
|
|
|
|
|
Serial.println(" bytes");
|
|
|
|
|
Serial.println("========================");
|
|
|
|
|
|
|
|
|
|
uint8_t pageBuffer[4] = {0, 0, 0, 0};
|
|
|
|
|
Serial.println("Beginne mit dem Schreiben der NDEF-Nachricht...");
|
|
|
|
|
|
|
|
|
@@ -375,15 +409,213 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
|
|
|
|
|
|
|
|
|
Serial.println("✓ Payload passt in den Tag - Schreibvorgang wird fortgesetzt");
|
|
|
|
|
|
|
|
|
|
// IMPORTANT: Use safe NDEF initialization instead of aggressive clearing
|
|
|
|
|
Serial.println("Schritt 1: Sichere NDEF-Initialisierung...");
|
|
|
|
|
// STEP 1: Read current tag content for debugging
|
|
|
|
|
Serial.println();
|
|
|
|
|
Serial.println("=== SCHRITT 1: NFC-INTERFACE-DIAGNOSE ===");
|
|
|
|
|
|
|
|
|
|
// First, check if the NFC interface is working at all
|
|
|
|
|
Serial.println("Teste NFC-Interface-Zustand...");
|
|
|
|
|
|
|
|
|
|
// Try to read capability container (which worked during detection)
|
|
|
|
|
uint8_t ccTest[4];
|
|
|
|
|
bool ccReadable = nfc.ntag2xx_ReadPage(3, ccTest);
|
|
|
|
|
Serial.print("Capability Container (Seite 3) lesbar: ");
|
|
|
|
|
Serial.println(ccReadable ? "✓" : "❌");
|
|
|
|
|
|
|
|
|
|
if (ccReadable) {
|
|
|
|
|
Serial.print("CC Inhalt: ");
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
if (ccTest[i] < 0x10) Serial.print("0");
|
|
|
|
|
Serial.print(ccTest[i], HEX);
|
|
|
|
|
Serial.print(" ");
|
|
|
|
|
}
|
|
|
|
|
Serial.println();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test a few different pages to see which ones are accessible
|
|
|
|
|
uint8_t testData[4];
|
|
|
|
|
for (uint8_t testPage = 0; testPage <= 10; testPage++) {
|
|
|
|
|
bool readable = nfc.ntag2xx_ReadPage(testPage, testData);
|
|
|
|
|
Serial.print("Seite ");
|
|
|
|
|
Serial.print(testPage);
|
|
|
|
|
Serial.print(": ");
|
|
|
|
|
if (readable) {
|
|
|
|
|
Serial.print("✓ - ");
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
if (testData[i] < 0x10) Serial.print("0");
|
|
|
|
|
Serial.print(testData[i], HEX);
|
|
|
|
|
Serial.print(" ");
|
|
|
|
|
}
|
|
|
|
|
Serial.println();
|
|
|
|
|
} else {
|
|
|
|
|
Serial.println("❌ - Nicht lesbar");
|
|
|
|
|
}
|
|
|
|
|
vTaskDelay(10 / portTICK_PERIOD_MS); // Small delay between reads
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.println("=== SCHRITT 2: AKTUELLER TAG-INHALT ===");
|
|
|
|
|
|
|
|
|
|
// Only read user data pages that are confirmed to be readable
|
|
|
|
|
for (uint8_t page = 4; page < 20; page++) {
|
|
|
|
|
uint8_t pageData[4];
|
|
|
|
|
if (nfc.ntag2xx_ReadPage(page, pageData)) {
|
|
|
|
|
Serial.print("Seite ");
|
|
|
|
|
Serial.print(page);
|
|
|
|
|
Serial.print(": ");
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
if (pageData[i] < 0x10) Serial.print("0");
|
|
|
|
|
Serial.print(pageData[i], HEX);
|
|
|
|
|
Serial.print(" ");
|
|
|
|
|
}
|
|
|
|
|
Serial.println();
|
|
|
|
|
} else {
|
|
|
|
|
Serial.print("Fehler beim Lesen von Seite ");
|
|
|
|
|
Serial.println(page);
|
|
|
|
|
// If we can't read basic user data pages, there's a fundamental problem
|
|
|
|
|
if (page <= 6) {
|
|
|
|
|
Serial.println("KRITISCHER FEHLER: Kann grundlegende User-Data-Seiten nicht lesen!");
|
|
|
|
|
Serial.println("Möglicherweise NFC-Interface-Problem oder Tag-Zustandsproblem");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
vTaskDelay(10 / portTICK_PERIOD_MS); // Small delay between reads
|
|
|
|
|
}
|
|
|
|
|
Serial.println("=========================================");
|
|
|
|
|
|
|
|
|
|
Serial.println();
|
|
|
|
|
Serial.println("=== SCHRITT 3: SCHREIBTEST ===");
|
|
|
|
|
Serial.println();
|
|
|
|
|
Serial.println("=== SCHRITT 3: SCHREIBTEST ===");
|
|
|
|
|
|
|
|
|
|
// If basic pages are not readable, try to reinitialize NFC interface
|
|
|
|
|
Serial.println("Versuche NFC-Interface zu stabilisieren...");
|
|
|
|
|
|
|
|
|
|
// Give the NFC interface time to stabilize
|
|
|
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
|
|
|
|
|
|
|
|
// Try to reestablish communication
|
|
|
|
|
bool interfaceOk = false;
|
|
|
|
|
for (int retry = 0; retry < 3; retry++) {
|
|
|
|
|
Serial.print("NFC-Interface Test ");
|
|
|
|
|
Serial.print(retry + 1);
|
|
|
|
|
Serial.print("/3... ");
|
|
|
|
|
|
|
|
|
|
uint8_t ccRetest[4];
|
|
|
|
|
if (nfc.ntag2xx_ReadPage(3, ccRetest)) {
|
|
|
|
|
Serial.println("✓");
|
|
|
|
|
interfaceOk = true;
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
Serial.println("❌");
|
|
|
|
|
vTaskDelay(200 / portTICK_PERIOD_MS);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!interfaceOk) {
|
|
|
|
|
Serial.println("FEHLER: NFC-Interface nicht stabil - Schreibvorgang abgebrochen");
|
|
|
|
|
oledShowMessage("NFC Interface Error");
|
|
|
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.println("NFC-Interface ist stabil - fahre mit Schreibtest fort");
|
|
|
|
|
|
|
|
|
|
uint8_t testPage[4] = {0xAA, 0xBB, 0xCC, 0xDD}; // Test pattern
|
|
|
|
|
|
|
|
|
|
if (!nfc.ntag2xx_WritePage(10, testPage)) { // Use page 10 for test
|
|
|
|
|
Serial.println("FEHLER: Einfacher Schreibtest fehlgeschlagen!");
|
|
|
|
|
Serial.println("Tag ist möglicherweise schreibgeschützt oder defekt");
|
|
|
|
|
|
|
|
|
|
// Additional diagnostics
|
|
|
|
|
Serial.println("=== ERWEITERTE DIAGNOSE ===");
|
|
|
|
|
|
|
|
|
|
// Check if this is a timing issue
|
|
|
|
|
Serial.println("Teste Tag-Erkennung erneut...");
|
|
|
|
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
|
uint8_t uidLength;
|
|
|
|
|
bool tagStillPresent = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000);
|
|
|
|
|
Serial.print("Tag noch erkannt: ");
|
|
|
|
|
Serial.println(tagStillPresent ? "✓" : "❌");
|
|
|
|
|
|
|
|
|
|
if (!tagStillPresent) {
|
|
|
|
|
Serial.println("URSACHE: Tag wurde während Schreibvorgang entfernt!");
|
|
|
|
|
oledShowMessage("Tag removed during write");
|
|
|
|
|
} else {
|
|
|
|
|
Serial.println("URSACHE: Tag ist vorhanden aber nicht beschreibbar");
|
|
|
|
|
Serial.println("Möglicherweise: Schreibschutz, Defekt, oder Timing-Problem");
|
|
|
|
|
oledShowMessage("Tag write protected?");
|
|
|
|
|
}
|
|
|
|
|
Serial.println("===============================");
|
|
|
|
|
|
|
|
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify test write
|
|
|
|
|
uint8_t readBack[4];
|
|
|
|
|
if (!nfc.ntag2xx_ReadPage(10, readBack)) {
|
|
|
|
|
Serial.println("FEHLER: Kann Testdaten nicht zurücklesen!");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool testSuccess = true;
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
if (readBack[i] != testPage[i]) {
|
|
|
|
|
testSuccess = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!testSuccess) {
|
|
|
|
|
Serial.println("FEHLER: Schreibtest fehlgeschlagen - Daten stimmen nicht überein!");
|
|
|
|
|
Serial.print("Geschrieben: ");
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
Serial.print(testPage[i], HEX); Serial.print(" ");
|
|
|
|
|
}
|
|
|
|
|
Serial.println();
|
|
|
|
|
Serial.print("Gelesen: ");
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
Serial.print(readBack[i], HEX); Serial.print(" ");
|
|
|
|
|
}
|
|
|
|
|
Serial.println();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.println("✓ Schreibtest erfolgreich - Tag ist beschreibbar");
|
|
|
|
|
Serial.println("================================");
|
|
|
|
|
|
|
|
|
|
// STEP 3: NDEF initialization with verification
|
|
|
|
|
Serial.println();
|
|
|
|
|
Serial.println("=== SCHRITT 3: NDEF-INITIALISIERUNG ===");
|
|
|
|
|
if (!initializeNdefStructure()) {
|
|
|
|
|
Serial.println("FEHLER: Konnte NDEF-Struktur nicht initialisieren!");
|
|
|
|
|
oledShowMessage("NDEF init failed");
|
|
|
|
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
Serial.println("✓ NDEF-Struktur sicher initialisiert");
|
|
|
|
|
|
|
|
|
|
// Verify NDEF initialization
|
|
|
|
|
uint8_t ndefCheck[8];
|
|
|
|
|
bool ndefVerified = true;
|
|
|
|
|
for (uint8_t page = 4; page < 6; page++) {
|
|
|
|
|
if (!nfc.ntag2xx_ReadPage(page, &ndefCheck[(page-4)*4])) {
|
|
|
|
|
ndefVerified = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ndefVerified) {
|
|
|
|
|
Serial.print("NDEF-Header nach Initialisierung: ");
|
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
|
|
|
if (ndefCheck[i] < 0x10) Serial.print("0");
|
|
|
|
|
Serial.print(ndefCheck[i], HEX);
|
|
|
|
|
Serial.print(" ");
|
|
|
|
|
}
|
|
|
|
|
Serial.println();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.println("✓ NDEF-Struktur initialisiert und verifiziert");
|
|
|
|
|
Serial.println("==========================================");
|
|
|
|
|
|
|
|
|
|
// Allocate memory for the complete TLV structure
|
|
|
|
|
uint8_t* tlvData = (uint8_t*) malloc(totalTlvSize);
|
|
|
|
@@ -444,7 +676,8 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
|
|
|
|
uint8_t pageNumber = 4;
|
|
|
|
|
uint16_t totalBytes = offset + 1;
|
|
|
|
|
|
|
|
|
|
Serial.println("Schritt 2: Schreibe neue NDEF-Daten...");
|
|
|
|
|
Serial.println();
|
|
|
|
|
Serial.println("=== SCHRITT 4: SCHREIBE NEUE NDEF-DATEN ===");
|
|
|
|
|
Serial.print("Schreibe ");
|
|
|
|
|
Serial.print(totalBytes);
|
|
|
|
|
Serial.print(" Bytes in ");
|
|
|
|
@@ -452,6 +685,13 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
|
|
|
|
Serial.println(" Seiten...");
|
|
|
|
|
|
|
|
|
|
while (bytesWritten < totalBytes && pageNumber <= maxWritablePage) {
|
|
|
|
|
// Additional safety check before writing each page
|
|
|
|
|
if (pageNumber > maxWritablePage) {
|
|
|
|
|
Serial.print("STOP: Reached maximum writable page ");
|
|
|
|
|
Serial.println(maxWritablePage);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clear page buffer
|
|
|
|
|
memset(pageBuffer, 0, 4);
|
|
|
|
|
|
|
|
|
@@ -467,6 +707,53 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
|
|
|
|
Serial.println(pageNumber);
|
|
|
|
|
Serial.print("Möglicherweise Page-Limit erreicht für ");
|
|
|
|
|
Serial.println(tagType);
|
|
|
|
|
Serial.print("Erwartetes Maximum: ");
|
|
|
|
|
Serial.println(maxWritablePage);
|
|
|
|
|
Serial.print("Tatsächliches Maximum scheint niedriger zu sein!");
|
|
|
|
|
|
|
|
|
|
// Update max page for future operations
|
|
|
|
|
if (pageNumber > 4) {
|
|
|
|
|
Serial.print("Setze neues Maximum auf Seite ");
|
|
|
|
|
Serial.println(pageNumber - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(tlvData);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IMMEDIATE verification after each write - this is critical!
|
|
|
|
|
Serial.print("Verifiziere Seite ");
|
|
|
|
|
Serial.print(pageNumber);
|
|
|
|
|
Serial.print("... ");
|
|
|
|
|
|
|
|
|
|
uint8_t verifyBuffer[4];
|
|
|
|
|
vTaskDelay(10 / portTICK_PERIOD_MS); // Small delay before verification
|
|
|
|
|
|
|
|
|
|
if (nfc.ntag2xx_ReadPage(pageNumber, verifyBuffer)) {
|
|
|
|
|
bool writeSuccess = true;
|
|
|
|
|
for (int i = 0; i < bytesToWrite; i++) {
|
|
|
|
|
if (verifyBuffer[i] != pageBuffer[i]) {
|
|
|
|
|
writeSuccess = false;
|
|
|
|
|
Serial.println();
|
|
|
|
|
Serial.print("VERIFIKATIONSFEHLER bei Byte ");
|
|
|
|
|
Serial.print(i);
|
|
|
|
|
Serial.print(" - Erwartet: 0x");
|
|
|
|
|
Serial.print(pageBuffer[i], HEX);
|
|
|
|
|
Serial.print(", Gelesen: 0x");
|
|
|
|
|
Serial.println(verifyBuffer[i], HEX);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!writeSuccess) {
|
|
|
|
|
Serial.println("❌ SCHREIBVORGANG FEHLGESCHLAGEN!");
|
|
|
|
|
free(tlvData);
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
Serial.println("✓");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Serial.println("❌ Kann Seite nicht zur Verifikation lesen!");
|
|
|
|
|
free(tlvData);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@@ -511,7 +798,129 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
|
|
|
|
Serial.print((bytesWritten * 100) / availableUserData);
|
|
|
|
|
Serial.println("%");
|
|
|
|
|
Serial.println("✓ Bestehende Daten wurden überschrieben");
|
|
|
|
|
|
|
|
|
|
// CRITICAL: Verify the write by reading back the data
|
|
|
|
|
Serial.println();
|
|
|
|
|
Serial.println("=== WRITE VERIFICATION ===");
|
|
|
|
|
|
|
|
|
|
// Wait a moment for tag to stabilize
|
|
|
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
|
|
|
|
|
|
|
|
// Read back the written data to verify
|
|
|
|
|
uint8_t verifyBuffer[totalBytes];
|
|
|
|
|
memset(verifyBuffer, 0, totalBytes);
|
|
|
|
|
|
|
|
|
|
bool verificationSuccess = true;
|
|
|
|
|
uint8_t verifyPage = 4;
|
|
|
|
|
uint16_t verifyBytesRead = 0;
|
|
|
|
|
|
|
|
|
|
while (verifyBytesRead < totalBytes && verifyPage <= maxWritablePage) {
|
|
|
|
|
uint8_t pageData[4];
|
|
|
|
|
if (!nfc.ntag2xx_ReadPage(verifyPage, pageData)) {
|
|
|
|
|
Serial.print("VERIFICATION FAILED: Cannot read page ");
|
|
|
|
|
Serial.println(verifyPage);
|
|
|
|
|
verificationSuccess = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy page data to verify buffer
|
|
|
|
|
uint16_t bytesToCopy = min(4, (int)(totalBytes - verifyBytesRead));
|
|
|
|
|
memcpy(&verifyBuffer[verifyBytesRead], pageData, bytesToCopy);
|
|
|
|
|
|
|
|
|
|
verifyBytesRead += bytesToCopy;
|
|
|
|
|
verifyPage++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (verificationSuccess && verifyBytesRead >= totalBytes) {
|
|
|
|
|
// Compare written data with read data
|
|
|
|
|
bool dataMatches = true;
|
|
|
|
|
for (uint16_t i = 0; i < totalBytes; i++) {
|
|
|
|
|
if (verifyBuffer[i] != tlvData[i]) {
|
|
|
|
|
Serial.print("VERIFICATION FAILED: Data mismatch at byte ");
|
|
|
|
|
Serial.print(i);
|
|
|
|
|
Serial.print(" - Expected: 0x");
|
|
|
|
|
Serial.print(tlvData[i], HEX);
|
|
|
|
|
Serial.print(", Read: 0x");
|
|
|
|
|
Serial.println(verifyBuffer[i], HEX);
|
|
|
|
|
dataMatches = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataMatches) {
|
|
|
|
|
Serial.println("✓ WRITE VERIFICATION SUCCESSFUL!");
|
|
|
|
|
Serial.println("✓ All written data verified correctly");
|
|
|
|
|
|
|
|
|
|
// Additional JSON verification - try to parse the written JSON
|
|
|
|
|
Serial.println("=== JSON VERIFICATION ===");
|
|
|
|
|
|
|
|
|
|
// Find and extract JSON from verified data
|
|
|
|
|
// Look for the JSON payload within the NDEF structure
|
|
|
|
|
bool jsonFound = false;
|
|
|
|
|
for (uint16_t i = 0; i < totalBytes - 10; i++) {
|
|
|
|
|
if (verifyBuffer[i] == '{') {
|
|
|
|
|
// Found potential JSON start
|
|
|
|
|
String extractedJson = "";
|
|
|
|
|
uint16_t jsonEnd = 0;
|
|
|
|
|
|
|
|
|
|
for (uint16_t j = i; j < totalBytes; j++) {
|
|
|
|
|
if (verifyBuffer[j] >= 32 && verifyBuffer[j] <= 126) {
|
|
|
|
|
extractedJson += (char)verifyBuffer[j];
|
|
|
|
|
if (verifyBuffer[j] == '}') {
|
|
|
|
|
jsonEnd = j;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.print("Extracted JSON from tag: ");
|
|
|
|
|
Serial.println(extractedJson);
|
|
|
|
|
|
|
|
|
|
// Try to parse the extracted JSON
|
|
|
|
|
JsonDocument testDoc;
|
|
|
|
|
DeserializationError error = deserializeJson(testDoc, extractedJson);
|
|
|
|
|
if (!error) {
|
|
|
|
|
Serial.println("✓ JSON VERIFICATION SUCCESSFUL!");
|
|
|
|
|
Serial.print("✓ JSON is valid and parseable");
|
|
|
|
|
|
|
|
|
|
if (testDoc["sm_id"].is<String>()) {
|
|
|
|
|
Serial.print(" - sm_id found: ");
|
|
|
|
|
Serial.println(testDoc["sm_id"].as<String>());
|
|
|
|
|
} else {
|
|
|
|
|
Serial.println(" - WARNING: sm_id not found in JSON!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jsonFound = true;
|
|
|
|
|
testDoc.clear();
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
Serial.print("JSON parse error: ");
|
|
|
|
|
Serial.println(error.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!jsonFound) {
|
|
|
|
|
Serial.println("WARNING: No valid JSON found in verified data!");
|
|
|
|
|
verificationSuccess = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
verificationSuccess = false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Serial.println("VERIFICATION FAILED: Could not read back all data");
|
|
|
|
|
verificationSuccess = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.println("=========================");
|
|
|
|
|
Serial.println();
|
|
|
|
|
|
|
|
|
|
if (!verificationSuccess) {
|
|
|
|
|
Serial.println("❌ WRITE FAILED - Data verification unsuccessful");
|
|
|
|
|
Serial.println("❌ Tag may not contain the expected data");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
@@ -759,6 +1168,79 @@ bool decodeNdefAndReturnJson(const byte* encodedMessage, String uidString) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool quickSpoolIdCheck(String uidString) {
|
|
|
|
|
// Fast-path: Read only first 2-3 pages to check for sm_id pattern
|
|
|
|
|
// This dramatically speeds up known spool recognition
|
|
|
|
|
|
|
|
|
|
// CRITICAL: Do not execute during write operations!
|
|
|
|
|
if (nfcWriteInProgress) {
|
|
|
|
|
Serial.println("FAST-PATH: Skipped during write operation");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.println("=== FAST-PATH: Quick sm_id Check ===");
|
|
|
|
|
|
|
|
|
|
// Read first 3 pages (12 bytes) after NDEF header (pages 4-6)
|
|
|
|
|
uint8_t quickData[12];
|
|
|
|
|
memset(quickData, 0, 12);
|
|
|
|
|
|
|
|
|
|
for (uint8_t page = 4; page < 7; page++) {
|
|
|
|
|
if (!nfc.ntag2xx_ReadPage(page, quickData + (page - 4) * 4)) {
|
|
|
|
|
Serial.print("Failed to read page ");
|
|
|
|
|
Serial.println(page);
|
|
|
|
|
return false; // Fall back to full read
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert to string for pattern matching
|
|
|
|
|
String quickCheck = "";
|
|
|
|
|
for (int i = 0; i < 12; i++) {
|
|
|
|
|
if (quickData[i] >= 32 && quickData[i] <= 126) {
|
|
|
|
|
quickCheck += (char)quickData[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.print("Quick data (first 12 bytes): ");
|
|
|
|
|
Serial.println(quickCheck);
|
|
|
|
|
|
|
|
|
|
// Look for sm_id pattern at the beginning
|
|
|
|
|
if (quickCheck.indexOf("\"sm_id\":\"") >= 0 && quickCheck.indexOf("\"sm_id\":\"0\"") < 0) {
|
|
|
|
|
Serial.println("✓ FAST-PATH: sm_id found in first bytes - known spool detected!");
|
|
|
|
|
|
|
|
|
|
// Extract sm_id from quick data if possible
|
|
|
|
|
int smIdStart = quickCheck.indexOf("\"sm_id\":\"") + 9;
|
|
|
|
|
int smIdEnd = quickCheck.indexOf("\"", smIdStart);
|
|
|
|
|
|
|
|
|
|
if (smIdEnd > smIdStart) {
|
|
|
|
|
String quickSpoolId = quickCheck.substring(smIdStart, smIdEnd);
|
|
|
|
|
Serial.print("✓ Quick extracted sm_id: ");
|
|
|
|
|
Serial.println(quickSpoolId);
|
|
|
|
|
|
|
|
|
|
// Set as active spool immediately
|
|
|
|
|
activeSpoolId = quickSpoolId;
|
|
|
|
|
lastSpoolId = activeSpoolId;
|
|
|
|
|
|
|
|
|
|
oledShowProgressBar(2, octoEnabled?5:4, "Known Spool", "Quick mode");
|
|
|
|
|
Serial.println("✓ FAST-PATH SUCCESS: Known spool processed quickly");
|
|
|
|
|
return true; // Skip full tag reading!
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for other quick patterns
|
|
|
|
|
if (quickCheck.indexOf("\"location\":\"") >= 0) {
|
|
|
|
|
Serial.println("✓ FAST-PATH: Location tag detected");
|
|
|
|
|
return false; // Need full read for location processing
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (quickCheck.indexOf("\"brand\":\"") >= 0 && quickCheck.indexOf("\"sm_id\":\"0\"") >= 0) {
|
|
|
|
|
Serial.println("✓ FAST-PATH: New brand filament detected (sm_id:0)");
|
|
|
|
|
return false; // Need full read for brand filament creation
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.println("✗ FAST-PATH: No recognizable pattern - falling back to full read");
|
|
|
|
|
return false; // Fall back to full tag reading
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void writeJsonToTag(void *parameter) {
|
|
|
|
|
NfcWriteParameterType* params = (NfcWriteParameterType*)parameter;
|
|
|
|
|
|
|
|
|
@@ -767,12 +1249,11 @@ void writeJsonToTag(void *parameter) {
|
|
|
|
|
Serial.println(params->payload);
|
|
|
|
|
|
|
|
|
|
nfcReaderState = NFC_WRITING;
|
|
|
|
|
nfcWriteInProgress = true; // Block high-level tag operations during write
|
|
|
|
|
|
|
|
|
|
// First request the reading task to be suspended and than wait until it responds
|
|
|
|
|
nfcReadingTaskSuspendRequest = true;
|
|
|
|
|
while(nfcReadingTaskSuspendState == false){
|
|
|
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
|
|
|
}
|
|
|
|
|
// Do NOT suspend the reading task - we need NFC interface for verification
|
|
|
|
|
// Just use nfcWriteInProgress to prevent scanning and fast-path operations
|
|
|
|
|
Serial.println("NFC Write Task starting - High-level operations blocked, low-level NFC available");
|
|
|
|
|
|
|
|
|
|
//pauseBambuMqttTask = true;
|
|
|
|
|
// aktualisieren der Website wenn sich der Status ändert
|
|
|
|
@@ -860,7 +1341,8 @@ void writeJsonToTag(void *parameter) {
|
|
|
|
|
sendWriteResult(nullptr, success);
|
|
|
|
|
sendNfcData();
|
|
|
|
|
|
|
|
|
|
nfcReadingTaskSuspendRequest = false;
|
|
|
|
|
// Only reset the write protection flag - reading task was never suspended
|
|
|
|
|
nfcWriteInProgress = false; // Re-enable high-level tag operations
|
|
|
|
|
pauseBambuMqttTask = false;
|
|
|
|
|
|
|
|
|
|
free(params->payload);
|
|
|
|
@@ -895,8 +1377,8 @@ void startWriteJsonToTag(const bool isSpoolTag, const char* payload) {
|
|
|
|
|
void scanRfidTask(void * parameter) {
|
|
|
|
|
Serial.println("RFID Task gestartet");
|
|
|
|
|
for(;;) {
|
|
|
|
|
// Wenn geschrieben wird Schleife aussetzen
|
|
|
|
|
if (nfcReaderState != NFC_WRITING && !nfcReadingTaskSuspendRequest && !booting)
|
|
|
|
|
// Skip scanning during write operations, but keep NFC interface active
|
|
|
|
|
if (nfcReaderState != NFC_WRITING && !nfcWriteInProgress && !nfcReadingTaskSuspendRequest && !booting)
|
|
|
|
|
{
|
|
|
|
|
nfcReadingTaskSuspendState = false;
|
|
|
|
|
yield();
|
|
|
|
@@ -938,6 +1420,18 @@ void scanRfidTask(void * parameter) {
|
|
|
|
|
|
|
|
|
|
if (uidLength == 7)
|
|
|
|
|
{
|
|
|
|
|
// Try fast-path detection first for known spools
|
|
|
|
|
if (quickSpoolIdCheck(uidString)) {
|
|
|
|
|
Serial.println("✓ FAST-PATH: Tag processed quickly, skipping full read");
|
|
|
|
|
pauseBambuMqttTask = false;
|
|
|
|
|
// Set reader back to idle for next scan
|
|
|
|
|
nfcReaderState = NFC_READ_SUCCESS;
|
|
|
|
|
delay(500); // Small delay before next scan
|
|
|
|
|
continue; // Skip full tag reading and continue scan loop
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.println("Continuing with full tag read after fast-path check");
|
|
|
|
|
|
|
|
|
|
uint16_t tagSize = readTagSize();
|
|
|
|
|
if(tagSize > 0)
|
|
|
|
|
{
|
|
|
|
@@ -1029,8 +1523,17 @@ void scanRfidTask(void * parameter) {
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
nfcReadingTaskSuspendState = true;
|
|
|
|
|
Serial.println("NFC Reading disabled");
|
|
|
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
|
|
|
|
|
|
// Different behavior for write protection vs. full suspension
|
|
|
|
|
if (nfcWriteInProgress) {
|
|
|
|
|
// During write: Just pause scanning, don't disable NFC interface
|
|
|
|
|
// Serial.println("NFC Scanning paused during write operation");
|
|
|
|
|
vTaskDelay(100 / portTICK_PERIOD_MS); // Shorter delay during write
|
|
|
|
|
} else {
|
|
|
|
|
// Full suspension requested
|
|
|
|
|
Serial.println("NFC Reading disabled");
|
|
|
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
yield();
|
|
|
|
|
}
|
|
|
|
|