From f1cdd3f41dbd1bd5aad94e8d888454a7d5698237 Mon Sep 17 00:00:00 2001 From: Manuel Weiser Date: Fri, 29 Aug 2025 09:46:08 +0200 Subject: [PATCH] feat: enhance NDEF decoding with detailed validation and debugging output --- src/nfc.cpp | 151 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 135 insertions(+), 16 deletions(-) diff --git a/src/nfc.cpp b/src/nfc.cpp index 42057e4..c942998 100644 --- a/src/nfc.cpp +++ b/src/nfc.cpp @@ -206,62 +206,169 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) { bool decodeNdefAndReturnJson(const byte* encodedMessage, String uidString) { oledShowProgressBar(1, octoEnabled?5:4, "Reading", "Decoding data"); - // Check for NDEF TLV (Type-Length-Value) structure - if (encodedMessage[0] != 0x03) { - Serial.println("Not a valid NDEF message (missing TLV tag 0x03)"); + // Debug: Print first 32 bytes of the raw data + Serial.println("Raw NDEF data (first 32 bytes):"); + for (int i = 0; i < 32; i++) { + if (encodedMessage[i] < 0x10) Serial.print("0"); + Serial.print(encodedMessage[i], HEX); + Serial.print(" "); + if ((i + 1) % 16 == 0) Serial.println(); + } + Serial.println(); + + // Look for the NDEF TLV structure starting from the beginning + int tlvOffset = 0; + bool foundNdefTlv = false; + + // Search for NDEF TLV (0x03) in the first few bytes + for (int i = 0; i < 16; i++) { + if (encodedMessage[i] == 0x03) { + tlvOffset = i; + foundNdefTlv = true; + Serial.print("Found NDEF TLV at offset: "); + Serial.println(tlvOffset); + break; + } + } + + if (!foundNdefTlv) { + Serial.println("No NDEF TLV found in tag data"); return false; } - // Get the total NDEF message length from TLV - byte ndefMessageLength = encodedMessage[1]; + // Get the NDEF message length from TLV + uint16_t ndefMessageLength = 0; + int ndefRecordOffset = 0; - // Skip TLV header (2 bytes) to get to NDEF record - const byte* ndefRecord = &encodedMessage[2]; + if (encodedMessage[tlvOffset + 1] == 0xFF) { + // Extended length format: next 2 bytes contain the actual length + ndefMessageLength = (encodedMessage[tlvOffset + 2] << 8) | encodedMessage[tlvOffset + 3]; + ndefRecordOffset = tlvOffset + 4; // Skip TLV tag + 0xFF + 2 length bytes + Serial.print("NDEF Message Length (extended): "); + } else { + // Standard length format: single byte contains the length + ndefMessageLength = encodedMessage[tlvOffset + 1]; + ndefRecordOffset = tlvOffset + 2; // Skip TLV tag + 1 length byte + Serial.print("NDEF Message Length (standard): "); + } + Serial.println(ndefMessageLength); + + // Get pointer to NDEF record + const byte* ndefRecord = &encodedMessage[ndefRecordOffset]; // Parse NDEF record header byte recordHeader = ndefRecord[0]; byte typeLength = ndefRecord[1]; + Serial.print("NDEF Record Header: 0x"); + Serial.println(recordHeader, HEX); + Serial.print("Type Length: "); + Serial.println(typeLength); + // Determine payload length (can be 1 or 4 bytes depending on SR flag) uint32_t payloadLength = 0; byte payloadLengthBytes = 1; + byte payloadLengthOffset = 2; - // Check if Short Record (SR) flag is set + // Check if Short Record (SR) flag is set (bit 4) if (recordHeader & 0x10) { // SR flag payloadLength = ndefRecord[2]; payloadLengthBytes = 1; + payloadLengthOffset = 2; } else { // Long record format (4 bytes for payload length) payloadLength = (ndefRecord[2] << 24) | (ndefRecord[3] << 16) | (ndefRecord[4] << 8) | ndefRecord[5]; payloadLengthBytes = 4; + payloadLengthOffset = 2; } - Serial.print("NDEF Record Header: 0x"); - Serial.println(recordHeader, HEX); - Serial.print("Type Length: "); - Serial.println(typeLength); Serial.print("Payload Length: "); Serial.println(payloadLength); + Serial.print("Payload Length Bytes: "); + Serial.println(payloadLengthBytes); + + // Check for ID field (if IL flag is set) + byte idLength = 0; + if (recordHeader & 0x08) { // IL flag + idLength = ndefRecord[payloadLengthOffset + payloadLengthBytes]; + Serial.print("ID Length: "); + Serial.println(idLength); + } // Calculate offset to payload - byte payloadOffset = 2 + payloadLengthBytes + typeLength; + byte payloadOffset = 1 + 1 + payloadLengthBytes + typeLength + idLength; + Serial.print("Calculated payload offset: "); + Serial.println(payloadOffset); + // Verify we have enough data - if (payloadOffset + payloadLength > ndefMessageLength + 2) { + if (payloadOffset + payloadLength > ndefMessageLength) { Serial.println("Invalid NDEF structure - payload extends beyond message"); + Serial.print("Payload offset + length: "); + Serial.print(payloadOffset + payloadLength); + Serial.print(", NDEF message length: "); + Serial.println(ndefMessageLength); return false; } + // Print the record type for debugging + Serial.print("Record Type: "); + for (int i = 0; i < typeLength; i++) { + Serial.print((char)ndefRecord[1 + 1 + payloadLengthBytes + i]); + } + Serial.println(); + nfcJsonData = ""; - // Extract JSON payload + // Extract JSON payload with validation + uint32_t actualJsonLength = 0; for (uint32_t i = 0; i < payloadLength; i++) { - nfcJsonData += (char)ndefRecord[payloadOffset + i]; + byte currentByte = ndefRecord[payloadOffset + i]; + + // Stop at null terminator or if we find the end of JSON + if (currentByte == 0x00) { + Serial.print("Found null terminator at position: "); + Serial.println(i); + break; + } + + // Only add printable characters and common JSON characters + if (currentByte >= 32 && currentByte <= 126) { + nfcJsonData += (char)currentByte; + actualJsonLength++; + } else { + Serial.print("Skipping non-printable byte at position "); + Serial.print(i); + Serial.print(": 0x"); + Serial.println(currentByte, HEX); + } + + // Check if we've reached the end of a JSON object + if (currentByte == '}') { + // Count opening and closing braces to detect complete JSON + int braceCount = 0; + for (uint32_t j = 0; j <= i; j++) { + if (ndefRecord[payloadOffset + j] == '{') braceCount++; + else if (ndefRecord[payloadOffset + j] == '}') braceCount--; + } + + if (braceCount == 0) { + Serial.print("Found complete JSON object at position: "); + Serial.println(i); + actualJsonLength = i + 1; + break; + } + } } + Serial.print("Actual JSON length extracted: "); + Serial.println(actualJsonLength); Serial.println("Decoded JSON Data:"); Serial.println(nfcJsonData); + + // Trim any trailing whitespace or invalid characters + nfcJsonData.trim(); // JSON-Dokument verarbeiten JsonDocument doc; @@ -566,6 +673,18 @@ void scanRfidTask(void * parameter) { Serial.println("Tag entfernt"); if (!bambuCredentials.autosend_enable) oledShowWeight(weight); } + // Reset state after successful read when tag is removed + else if (!success && nfcReaderState == NFC_READ_SUCCESS) + { + nfcReaderState = NFC_IDLE; + Serial.println("Tag nach erfolgreichem Lesen entfernt - bereit für nächsten Tag"); + } + + // Add a longer pause after successful reading to prevent immediate re-reading + if (nfcReaderState == NFC_READ_SUCCESS) { + Serial.println("Tag erfolgreich gelesen - warte 5 Sekunden vor nächstem Scan"); + vTaskDelay(5000 / portTICK_PERIOD_MS); // 5 second pause + } // aktualisieren der Website wenn sich der Status ändert sendNfcData();