1883 lines
64 KiB
C++
1883 lines
64 KiB
C++
#include "nfc.h"
|
|
#include <Arduino.h>
|
|
#include <Adafruit_PN532.h>
|
|
#include <ArduinoJson.h>
|
|
#include "config.h"
|
|
#include "website.h"
|
|
#include "api.h"
|
|
#include "esp_task_wdt.h"
|
|
#include "scale.h"
|
|
#include "bambu.h"
|
|
#include "main.h"
|
|
|
|
//Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);
|
|
Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);
|
|
|
|
TaskHandle_t RfidReaderTask;
|
|
|
|
JsonDocument rfidData;
|
|
String activeSpoolId = "";
|
|
String lastSpoolId = "";
|
|
String nfcJsonData = "";
|
|
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;
|
|
char* payload;
|
|
};
|
|
|
|
volatile nfcReaderStateType nfcReaderState = NFC_IDLE;
|
|
// 0 = nicht gelesen
|
|
// 1 = erfolgreich gelesen
|
|
// 2 = fehler beim Lesen
|
|
// 3 = schreiben
|
|
// 4 = fehler beim Schreiben
|
|
// 5 = erfolgreich geschrieben
|
|
// 6 = reading
|
|
// ***** PN532
|
|
|
|
// ##### Funktionen für RFID #####
|
|
void payloadToJson(uint8_t *data) {
|
|
const char* startJson = strchr((char*)data, '{');
|
|
const char* endJson = strrchr((char*)data, '}');
|
|
|
|
if (startJson && endJson && endJson > startJson) {
|
|
String jsonString = String(startJson, endJson - startJson + 1);
|
|
//Serial.print("Bereinigter JSON-String: ");
|
|
//Serial.println(jsonString);
|
|
|
|
// JSON-Dokument verarbeiten
|
|
JsonDocument doc; // Passen Sie die Größe an den JSON-Inhalt an
|
|
DeserializationError error = deserializeJson(doc, jsonString);
|
|
|
|
if (!error) {
|
|
const char* color_hex = doc["color_hex"];
|
|
const char* type = doc["type"];
|
|
int min_temp = doc["min_temp"];
|
|
int max_temp = doc["max_temp"];
|
|
const char* brand = doc["brand"];
|
|
|
|
Serial.println();
|
|
Serial.println("-----------------");
|
|
Serial.println("JSON-Parsed Data:");
|
|
Serial.println(color_hex);
|
|
Serial.println(type);
|
|
Serial.println(min_temp);
|
|
Serial.println(max_temp);
|
|
Serial.println(brand);
|
|
Serial.println("-----------------");
|
|
Serial.println();
|
|
} else {
|
|
Serial.print("deserializeJson() failed: ");
|
|
Serial.println(error.f_str());
|
|
}
|
|
|
|
doc.clear();
|
|
} else {
|
|
Serial.println("Kein gültiger JSON-Inhalt gefunden oder fehlerhafte Formatierung.");
|
|
//writeJsonToTag("{\"version\":\"1.0\",\"protocol\":\"NFC\",\"color_hex\":\"#FFFFFF\",\"type\":\"Example\",\"min_temp\":10,\"max_temp\":30,\"brand\":\"BrandName\"}");
|
|
}
|
|
}
|
|
|
|
bool formatNdefTag() {
|
|
uint8_t ndefInit[] = { 0x03, 0x00, 0xFE }; // NDEF Initialisierungsnachricht
|
|
bool success = true;
|
|
int pageOffset = 4; // Startseite für NDEF-Daten auf NTAG2xx
|
|
|
|
Serial.println();
|
|
Serial.println("Formatiere NDEF-Tag...");
|
|
|
|
// Schreibe die Initialisierungsnachricht auf die ersten Seiten
|
|
for (int i = 0; i < sizeof(ndefInit); i += 4) {
|
|
if (!nfc.ntag2xx_WritePage(pageOffset + (i / 4), &ndefInit[i])) {
|
|
success = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}uint16_t readTagSize()
|
|
{
|
|
uint8_t buffer[4];
|
|
memset(buffer, 0, 4);
|
|
nfc.ntag2xx_ReadPage(3, buffer);
|
|
return buffer[2]*8;
|
|
}
|
|
|
|
String detectNtagType()
|
|
{
|
|
// Read capability container from page 3 to determine exact NTAG type
|
|
uint8_t ccBuffer[4];
|
|
memset(ccBuffer, 0, 4);
|
|
|
|
if (!nfc.ntag2xx_ReadPage(3, ccBuffer)) {
|
|
Serial.println("Failed to read capability container");
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
// Also read configuration pages to get more info
|
|
uint8_t configBuffer[4];
|
|
memset(configBuffer, 0, 4);
|
|
|
|
Serial.print("Capability Container: ");
|
|
for (int i = 0; i < 4; i++) {
|
|
if (ccBuffer[i] < 0x10) Serial.print("0");
|
|
Serial.print(ccBuffer[i], HEX);
|
|
Serial.print(" ");
|
|
}
|
|
Serial.println();
|
|
|
|
// NTAG type detection based on capability container
|
|
// CC[2] contains the data area size in bytes / 8
|
|
uint16_t dataAreaSize = ccBuffer[2] * 8;
|
|
|
|
Serial.print("Data area size from CC: ");
|
|
Serial.println(dataAreaSize);
|
|
|
|
// Try to read different configuration pages to determine exact type
|
|
String tagType = "UNKNOWN";
|
|
|
|
// Try to read page 41 (NTAG213 ends at page 39, so this should fail)
|
|
uint8_t testBuffer[4];
|
|
bool canReadPage41 = nfc.ntag2xx_ReadPage(41, testBuffer);
|
|
|
|
// Try to read page 130 (NTAG215 ends at page 129, so this should fail for NTAG213/215)
|
|
bool canReadPage130 = nfc.ntag2xx_ReadPage(130, testBuffer);
|
|
|
|
if (dataAreaSize <= 180 && !canReadPage41) {
|
|
tagType = "NTAG213";
|
|
Serial.println("Detected: NTAG213 (cannot read beyond page 39)");
|
|
} else if (dataAreaSize <= 540 && canReadPage41 && !canReadPage130) {
|
|
tagType = "NTAG215";
|
|
Serial.println("Detected: NTAG215 (can read page 41, cannot read page 130)");
|
|
} else if (dataAreaSize <= 928 && canReadPage130) {
|
|
tagType = "NTAG216";
|
|
Serial.println("Detected: NTAG216 (can read page 130)");
|
|
} else {
|
|
// Fallback: use data area size from capability container
|
|
if (dataAreaSize <= 180) {
|
|
tagType = "NTAG213";
|
|
Serial.println("Fallback detection: NTAG213 based on data area size");
|
|
} else if (dataAreaSize <= 540) {
|
|
tagType = "NTAG215";
|
|
Serial.println("Fallback detection: NTAG215 based on data area size");
|
|
} else {
|
|
tagType = "NTAG216";
|
|
Serial.println("Fallback detection: NTAG216 based on data area size");
|
|
}
|
|
}
|
|
|
|
return tagType;
|
|
}
|
|
|
|
uint16_t getAvailableUserDataSize()
|
|
{
|
|
String tagType = detectNtagType();
|
|
uint16_t userDataSize = 0;
|
|
|
|
if (tagType == "NTAG213") {
|
|
// NTAG213: User data from page 4-39 (36 pages * 4 bytes = 144 bytes)
|
|
userDataSize = 144;
|
|
Serial.println("NTAG213 confirmed - 144 bytes user data available");
|
|
} else if (tagType == "NTAG215") {
|
|
// NTAG215: User data from page 4-129 (126 pages * 4 bytes = 504 bytes)
|
|
userDataSize = 504;
|
|
Serial.println("NTAG215 confirmed - 504 bytes user data available");
|
|
} else if (tagType == "NTAG216") {
|
|
// NTAG216: User data from page 4-225 (222 pages * 4 bytes = 888 bytes)
|
|
userDataSize = 888;
|
|
Serial.println("NTAG216 confirmed - 888 bytes user data available");
|
|
} else {
|
|
// Unknown tag type, use conservative estimate
|
|
uint16_t tagSize = readTagSize();
|
|
userDataSize = tagSize - 60; // Reserve 60 bytes for headers/config
|
|
Serial.print("Unknown NTAG type, using conservative estimate: ");
|
|
Serial.println(userDataSize);
|
|
}
|
|
|
|
return userDataSize;
|
|
}
|
|
|
|
uint16_t getMaxUserDataPages()
|
|
{
|
|
String tagType = detectNtagType();
|
|
uint16_t maxPages = 0;
|
|
|
|
if (tagType == "NTAG213") {
|
|
maxPages = 39; // Pages 4-39 are user data
|
|
} else if (tagType == "NTAG215") {
|
|
maxPages = 129; // Pages 4-129 are user data
|
|
} else if (tagType == "NTAG216") {
|
|
maxPages = 225; // Pages 4-225 are user data
|
|
} else {
|
|
// Conservative fallback
|
|
maxPages = 39;
|
|
Serial.println("Unknown tag type, using NTAG213 page limit as fallback");
|
|
}
|
|
|
|
Serial.print("Maximum writable page: ");
|
|
Serial.println(maxPages);
|
|
return maxPages;
|
|
}
|
|
|
|
bool initializeNdefStructure() {
|
|
// Write minimal NDEF structure without destroying the tag
|
|
// This creates a clean slate while preserving tag functionality
|
|
|
|
Serial.println("Initialisiere sichere NDEF-Struktur...");
|
|
|
|
// Minimal NDEF structure: TLV with empty message
|
|
uint8_t minimalNdef[8] = {
|
|
0x03, // NDEF Message TLV Tag
|
|
0x03, // Length (3 bytes for minimal empty record)
|
|
0xD0, // NDEF Record Header (TNF=0x0:Empty + SR + ME + MB)
|
|
0x00, // Type Length (0 = empty record)
|
|
0x00, // Payload Length (0 = empty record)
|
|
0xFE, // Terminator TLV
|
|
0x00, 0x00 // Padding
|
|
};
|
|
|
|
// Write the minimal structure starting at page 4
|
|
uint8_t pageBuffer[4];
|
|
|
|
for (int i = 0; i < 8; i += 4) {
|
|
memcpy(pageBuffer, &minimalNdef[i], 4);
|
|
|
|
if (!nfc.ntag2xx_WritePage(4 + (i / 4), pageBuffer)) {
|
|
Serial.print("Fehler beim Initialisieren von Seite ");
|
|
Serial.println(4 + (i / 4));
|
|
return false;
|
|
}
|
|
|
|
Serial.print("Seite ");
|
|
Serial.print(4 + (i / 4));
|
|
Serial.print(" initialisiert: ");
|
|
for (int j = 0; j < 4; j++) {
|
|
if (pageBuffer[j] < 0x10) Serial.print("0");
|
|
Serial.print(pageBuffer[j], HEX);
|
|
Serial.print(" ");
|
|
}
|
|
Serial.println();
|
|
}
|
|
|
|
Serial.println("✓ Sichere NDEF-Struktur initialisiert");
|
|
Serial.println("✓ Tag bleibt funktionsfähig und überschreibbar");
|
|
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();
|
|
uint16_t tagSize = readTagSize();
|
|
uint16_t availableUserData = getAvailableUserDataSize();
|
|
uint16_t maxWritablePage = getMaxUserDataPages();
|
|
|
|
Serial.println("=== NFC TAG ANALYSIS ===");
|
|
Serial.print("Tag Type: ");Serial.println(tagType);
|
|
Serial.print("Total Tag Size: ");Serial.println(tagSize);
|
|
Serial.print("Available User Data: ");Serial.println(availableUserData);
|
|
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 with optimized approach
|
|
uint16_t actualMaxPage = maxWritablePage;
|
|
Serial.println("Searching for actual maximum writable page...");
|
|
|
|
// Use binary search approach for faster page limit detection
|
|
uint16_t lowPage = 4;
|
|
uint16_t highPage = maxWritablePage;
|
|
uint16_t testAttempts = 0;
|
|
const uint16_t maxTestAttempts = 15; // Limit search attempts
|
|
|
|
while (lowPage <= highPage && testAttempts < maxTestAttempts) {
|
|
uint16_t midPage = (lowPage + highPage) / 2;
|
|
testAttempts++;
|
|
|
|
Serial.print("Testing page ");
|
|
Serial.print(midPage);
|
|
Serial.print(" (attempt ");
|
|
Serial.print(testAttempts);
|
|
Serial.print("/");
|
|
Serial.print(maxTestAttempts);
|
|
Serial.print(")... ");
|
|
|
|
if (nfc.ntag2xx_ReadPage(midPage, testBuffer)) {
|
|
Serial.println("✓");
|
|
actualMaxPage = midPage;
|
|
lowPage = midPage + 1; // Search higher
|
|
} else {
|
|
Serial.println("❌");
|
|
highPage = midPage - 1; // Search lower
|
|
}
|
|
|
|
// Small delay to prevent interface overload
|
|
vTaskDelay(5 / portTICK_PERIOD_MS);
|
|
yield();
|
|
}
|
|
|
|
Serial.print("Found actual max readable page: ");
|
|
Serial.println(actualMaxPage);
|
|
Serial.print("Search completed in ");
|
|
Serial.print(testAttempts);
|
|
Serial.println(" attempts");
|
|
|
|
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...");
|
|
|
|
// Figure out how long the string is
|
|
uint16_t payloadLen = strlen(payload);
|
|
Serial.print("Länge der Payload: ");
|
|
Serial.println(payloadLen);
|
|
|
|
Serial.print("Payload: ");Serial.println(payload);
|
|
|
|
// MIME type for JSON
|
|
const char mimeType[] = "application/json";
|
|
uint8_t mimeTypeLen = strlen(mimeType);
|
|
|
|
// Calculate NDEF record size
|
|
uint8_t ndefRecordHeaderSize = 3; // Header byte + Type Length + Payload Length (short record)
|
|
uint16_t ndefRecordSize = ndefRecordHeaderSize + mimeTypeLen + payloadLen;
|
|
|
|
// Calculate TLV size - need to check if we need extended length format
|
|
uint8_t tlvHeaderSize;
|
|
uint16_t totalTlvSize;
|
|
|
|
if (ndefRecordSize <= 254) {
|
|
// Standard TLV format: Tag (1) + Length (1) + Value (ndefRecordSize)
|
|
tlvHeaderSize = 2;
|
|
totalTlvSize = tlvHeaderSize + ndefRecordSize + 1; // +1 for terminator TLV
|
|
} else {
|
|
// Extended TLV format: Tag (1) + 0xFF + Length (2) + Value (ndefRecordSize)
|
|
tlvHeaderSize = 4;
|
|
totalTlvSize = tlvHeaderSize + ndefRecordSize + 1; // +1 for terminator TLV
|
|
}
|
|
|
|
Serial.print("NDEF Record Size: ");
|
|
Serial.println(ndefRecordSize);
|
|
Serial.print("Total TLV Size: ");
|
|
Serial.println(totalTlvSize);
|
|
|
|
// Check if the message fits in the available user data space
|
|
if (totalTlvSize > availableUserData) {
|
|
Serial.println();
|
|
Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
Serial.println("FEHLER: Payload zu groß für diesen Tag-Typ!");
|
|
Serial.print("Tag-Typ: ");Serial.println(tagType);
|
|
Serial.print("Benötigt: ");Serial.print(totalTlvSize);Serial.println(" Bytes");
|
|
Serial.print("Verfügbar: ");Serial.print(availableUserData);Serial.println(" Bytes");
|
|
Serial.print("Überschuss: ");Serial.print(totalTlvSize - availableUserData);Serial.println(" Bytes");
|
|
|
|
if (tagType == "NTAG213") {
|
|
Serial.println("EMPFEHLUNG: Verwenden Sie einen NTAG215 (504 Bytes) oder NTAG216 (888 Bytes) Tag!");
|
|
Serial.println("Oder kürzen Sie die Payload um mindestens " + String(totalTlvSize - availableUserData) + " Bytes.");
|
|
}
|
|
Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!");
|
|
Serial.println();
|
|
|
|
oledShowMessage("Tag zu klein für Payload");
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
return 0;
|
|
}
|
|
|
|
Serial.println("✓ Payload passt in den Tag - Schreibvorgang wird fortgesetzt");
|
|
|
|
// STEP 1: NFC Interface Reset and Reinitialization
|
|
Serial.println();
|
|
Serial.println("=== SCHRITT 1: NFC-INTERFACE RESET UND NEUINITIALISIERUNG ===");
|
|
|
|
// First, check if the NFC interface is working at all
|
|
Serial.println("Teste aktuellen 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.println("❌ NFC-Interface ist nicht funktionsfähig - führe Reset durch");
|
|
|
|
// Perform NFC interface reset and reinitialization
|
|
Serial.println("Führe NFC-Interface Reset durch...");
|
|
|
|
// Step 1: Try to reinitialize the NFC interface completely
|
|
Serial.println("1. Neuinitialisierung des PN532...");
|
|
|
|
// Reinitialize the PN532
|
|
nfc.begin();
|
|
vTaskDelay(500 / portTICK_PERIOD_MS); // Give it time to initialize
|
|
|
|
// Check firmware version to ensure communication is working
|
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
|
if (versiondata) {
|
|
Serial.print("PN532 Firmware Version: 0x");
|
|
Serial.println(versiondata, HEX);
|
|
Serial.println("✓ PN532 Kommunikation wiederhergestellt");
|
|
} else {
|
|
Serial.println("❌ PN532 Kommunikation fehlgeschlagen");
|
|
oledShowMessage("NFC Reset failed");
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
return 0;
|
|
}
|
|
|
|
// Step 2: Reconfigure SAM
|
|
Serial.println("2. SAM-Konfiguration...");
|
|
nfc.SAMConfig();
|
|
vTaskDelay(200 / portTICK_PERIOD_MS);
|
|
|
|
// Step 3: Re-detect the tag
|
|
Serial.println("3. Tag-Wiedererkennung...");
|
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
|
|
uint8_t uidLength;
|
|
bool tagRedetected = false;
|
|
|
|
for (int attempts = 0; attempts < 5; attempts++) {
|
|
Serial.print("Tag-Erkennungsversuch ");
|
|
Serial.print(attempts + 1);
|
|
Serial.print("/5... ");
|
|
|
|
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000)) {
|
|
Serial.println("✓");
|
|
tagRedetected = true;
|
|
break;
|
|
} else {
|
|
Serial.println("❌");
|
|
vTaskDelay(300 / portTICK_PERIOD_MS);
|
|
}
|
|
}
|
|
|
|
if (!tagRedetected) {
|
|
Serial.println("❌ Tag konnte nach Reset nicht wiedererkannt werden");
|
|
oledShowMessage("Tag lost after reset");
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
return 0;
|
|
}
|
|
|
|
Serial.println("✓ Tag erfolgreich wiedererkannt");
|
|
|
|
// Step 4: Test basic page reading
|
|
Serial.println("4. Test der Grundfunktionalität...");
|
|
vTaskDelay(200 / portTICK_PERIOD_MS); // Give interface time to stabilize
|
|
|
|
ccReadable = nfc.ntag2xx_ReadPage(3, ccTest);
|
|
Serial.print("Capability Container nach Reset lesbar: ");
|
|
Serial.println(ccReadable ? "✓" : "❌");
|
|
|
|
if (!ccReadable) {
|
|
Serial.println("❌ NFC-Interface funktioniert nach Reset immer noch nicht");
|
|
oledShowMessage("NFC still broken");
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
return 0;
|
|
}
|
|
|
|
Serial.println("✓ NFC-Interface erfolgreich wiederhergestellt");
|
|
} else {
|
|
Serial.println("✓ NFC-Interface ist funktionsfähig");
|
|
}
|
|
|
|
// Display CC content for debugging
|
|
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();
|
|
}
|
|
|
|
Serial.println("=== SCHRITT 2: INTERFACE-FUNKTIONSTEST ===");
|
|
|
|
// Test a few critical pages to ensure stable operation
|
|
uint8_t testData[4];
|
|
bool basicPagesReadable = true;
|
|
|
|
for (uint8_t testPage = 0; testPage <= 6; 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");
|
|
if (testPage >= 3 && testPage <= 6) { // Critical pages for NDEF
|
|
basicPagesReadable = false;
|
|
}
|
|
}
|
|
vTaskDelay(10 / portTICK_PERIOD_MS); // Small delay between reads
|
|
}
|
|
|
|
if (!basicPagesReadable) {
|
|
Serial.println("❌ KRITISCHER FEHLER: Grundlegende NDEF-Seiten nicht lesbar!");
|
|
Serial.println("Tag oder Interface ist defekt");
|
|
oledShowMessage("Tag/Interface defect");
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
return 0;
|
|
}
|
|
|
|
Serial.println("✓ Alle kritischen Seiten sind lesbar");
|
|
Serial.println("===================================================");
|
|
|
|
Serial.println();
|
|
Serial.println("=== SCHRITT 3: SCHREIBBEREITSCHAFTSTEST ===");
|
|
|
|
// Test write capabilities before attempting the full write
|
|
Serial.println("Teste Schreibfähigkeiten des Tags...");
|
|
|
|
uint8_t testPage[4] = {0xAA, 0xBB, 0xCC, 0xDD}; // Test pattern
|
|
uint8_t originalPage[4]; // Store original content
|
|
|
|
// First, read original content of test page
|
|
if (!nfc.ntag2xx_ReadPage(10, originalPage)) {
|
|
Serial.println("FEHLER: Kann Testseite nicht lesen für Backup");
|
|
oledShowMessage("Test page read error");
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
return 0;
|
|
}
|
|
|
|
Serial.print("Original Inhalt Seite 10: ");
|
|
for (int i = 0; i < 4; i++) {
|
|
if (originalPage[i] < 0x10) Serial.print("0");
|
|
Serial.print(originalPage[i], HEX);
|
|
Serial.print(" ");
|
|
}
|
|
Serial.println();
|
|
|
|
// Perform write test
|
|
if (!nfc.ntag2xx_WritePage(10, testPage)) {
|
|
Serial.println("FEHLER: Schreibtest fehlgeschlagen!");
|
|
Serial.println("Tag ist möglicherweise schreibgeschützt oder defekt");
|
|
|
|
// Additional diagnostics
|
|
Serial.println("=== ERWEITERTE SCHREIBTEST-DIAGNOSE ===");
|
|
|
|
// Check if tag is still present
|
|
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 Schreibtest entfernt!");
|
|
oledShowMessage("Tag removed");
|
|
} else {
|
|
Serial.println("URSACHE: Tag ist vorhanden aber nicht beschreibbar");
|
|
Serial.println("Möglicherweise: Schreibschutz, Defekt, oder Interface-Problem");
|
|
oledShowMessage("Tag write protected?");
|
|
}
|
|
Serial.println("==========================================");
|
|
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
return 0;
|
|
}
|
|
|
|
// Verify test write
|
|
uint8_t readBack[4];
|
|
vTaskDelay(20 / portTICK_PERIOD_MS); // Wait for write to complete
|
|
|
|
if (!nfc.ntag2xx_ReadPage(10, readBack)) {
|
|
Serial.println("FEHLER: Kann Testdaten nicht zurücklesen!");
|
|
oledShowMessage("Test verify failed");
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
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;
|
|
}
|
|
|
|
// Restore original content
|
|
Serial.println("Stelle ursprünglichen Inhalt wieder her...");
|
|
if (!nfc.ntag2xx_WritePage(10, originalPage)) {
|
|
Serial.println("WARNUNG: Konnte ursprünglichen Inhalt nicht wiederherstellen!");
|
|
} else {
|
|
Serial.println("✓ Ursprünglicher Inhalt wiederhergestellt");
|
|
}
|
|
|
|
Serial.println("✓ Schreibtest erfolgreich - Tag ist voll funktionsfähig");
|
|
Serial.println("======================================================");
|
|
|
|
// STEP 4: NDEF initialization with verification
|
|
Serial.println();
|
|
Serial.println("=== SCHRITT 4: NDEF-INITIALISIERUNG ===");
|
|
if (!initializeNdefStructure()) {
|
|
Serial.println("FEHLER: Konnte NDEF-Struktur nicht initialisieren!");
|
|
oledShowMessage("NDEF init failed");
|
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
|
return 0;
|
|
}
|
|
|
|
// 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("==========================================");
|
|
|
|
// STEP 5: Allow interface to stabilize before major write operation
|
|
Serial.println();
|
|
Serial.println("=== SCHRITT 5: NFC-INTERFACE STABILISIERUNG ===");
|
|
Serial.println("Stabilisiere NFC-Interface vor Hauptschreibvorgang...");
|
|
|
|
// Give the interface time to fully settle after NDEF initialization
|
|
vTaskDelay(200 / portTICK_PERIOD_MS);
|
|
|
|
// Test interface stability with a simple read
|
|
uint8_t stabilityTest[4];
|
|
bool interfaceStable = false;
|
|
for (int attempts = 0; attempts < 3; attempts++) {
|
|
if (nfc.ntag2xx_ReadPage(4, stabilityTest)) {
|
|
Serial.print("Interface stability test ");
|
|
Serial.print(attempts + 1);
|
|
Serial.println("/3: ✓");
|
|
interfaceStable = true;
|
|
break;
|
|
} else {
|
|
Serial.print("Interface stability test ");
|
|
Serial.print(attempts + 1);
|
|
Serial.println("/3: ❌");
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
}
|
|
}
|
|
|
|
if (!interfaceStable) {
|
|
Serial.println("FEHLER: NFC-Interface ist nicht stabil genug für Schreibvorgang");
|
|
oledShowMessage("NFC Interface unstable");
|
|
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
|
return 0;
|
|
}
|
|
|
|
Serial.println("✓ NFC-Interface ist stabil - Schreibvorgang kann beginnen");
|
|
Serial.println("=========================================================");
|
|
|
|
// Allocate memory for the complete TLV structure
|
|
uint8_t* tlvData = (uint8_t*) malloc(totalTlvSize);
|
|
if (tlvData == NULL) {
|
|
Serial.println("Fehler: Nicht genug Speicher für TLV-Daten vorhanden.");
|
|
oledShowMessage("Memory error");
|
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
|
return 0;
|
|
}
|
|
|
|
// Build TLV structure
|
|
uint16_t offset = 0;
|
|
|
|
// TLV Header
|
|
tlvData[offset++] = 0x03; // NDEF Message TLV Tag
|
|
|
|
if (ndefRecordSize <= 254) {
|
|
// Standard length format
|
|
tlvData[offset++] = (uint8_t)ndefRecordSize;
|
|
} else {
|
|
// Extended length format
|
|
tlvData[offset++] = 0xFF;
|
|
tlvData[offset++] = (uint8_t)(ndefRecordSize >> 8); // High byte
|
|
tlvData[offset++] = (uint8_t)(ndefRecordSize & 0xFF); // Low byte
|
|
}
|
|
|
|
// NDEF Record Header
|
|
tlvData[offset++] = 0xD2; // NDEF Record Header (TNF=0x2:MIME Media + SR + ME + MB)
|
|
tlvData[offset++] = mimeTypeLen; // Type Length
|
|
tlvData[offset++] = (uint8_t)payloadLen; // Payload Length (short record format)
|
|
|
|
// MIME Type
|
|
memcpy(&tlvData[offset], mimeType, mimeTypeLen);
|
|
offset += mimeTypeLen;
|
|
|
|
// JSON Payload
|
|
memcpy(&tlvData[offset], payload, payloadLen);
|
|
offset += payloadLen;
|
|
|
|
// Terminator TLV
|
|
tlvData[offset] = 0xFE;
|
|
|
|
Serial.print("Gesamt-TLV-Länge: ");
|
|
Serial.println(offset + 1);
|
|
|
|
// Debug: Print first 64 bytes of TLV data
|
|
Serial.println("TLV Daten (erste 64 Bytes):");
|
|
for (int i = 0; i < min((int)(offset + 1), 64); i++) {
|
|
if (tlvData[i] < 0x10) Serial.print("0");
|
|
Serial.print(tlvData[i], HEX);
|
|
Serial.print(" ");
|
|
if ((i + 1) % 16 == 0) Serial.println();
|
|
}
|
|
Serial.println();
|
|
|
|
// Write data to tag pages (starting from page 4)
|
|
uint16_t bytesWritten = 0;
|
|
uint8_t pageNumber = 4;
|
|
uint16_t totalBytes = offset + 1;
|
|
|
|
Serial.println();
|
|
Serial.println("=== SCHRITT 6: SCHREIBE NEUE NDEF-DATEN ===");
|
|
Serial.print("Schreibe ");
|
|
Serial.print(totalBytes);
|
|
Serial.print(" Bytes in ");
|
|
Serial.print((totalBytes + 3) / 4); // Round up division
|
|
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);
|
|
|
|
// Calculate how many bytes to write to this page
|
|
uint16_t bytesToWrite = min(4, (int)(totalBytes - bytesWritten));
|
|
|
|
// Copy data to page buffer
|
|
memcpy(pageBuffer, &tlvData[bytesWritten], bytesToWrite);
|
|
|
|
// Write page to tag with retry mechanism
|
|
bool writeSuccess = false;
|
|
for (int writeAttempt = 0; writeAttempt < 3; writeAttempt++) {
|
|
if (nfc.ntag2xx_WritePage(pageNumber, pageBuffer)) {
|
|
writeSuccess = true;
|
|
break;
|
|
} else {
|
|
Serial.print("Schreibversuch ");
|
|
Serial.print(writeAttempt + 1);
|
|
Serial.print("/3 für Seite ");
|
|
Serial.print(pageNumber);
|
|
Serial.println(" fehlgeschlagen");
|
|
|
|
if (writeAttempt < 2) {
|
|
vTaskDelay(50 / portTICK_PERIOD_MS); // Wait before retry
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!writeSuccess) {
|
|
Serial.print("FEHLER beim Schreiben der Seite ");
|
|
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(20 / portTICK_PERIOD_MS); // Increased delay before verification
|
|
|
|
// Verification with retry mechanism
|
|
bool verifySuccess = false;
|
|
for (int verifyAttempt = 0; verifyAttempt < 3; verifyAttempt++) {
|
|
if (nfc.ntag2xx_ReadPage(pageNumber, verifyBuffer)) {
|
|
bool writeMatches = true;
|
|
for (int i = 0; i < bytesToWrite; i++) {
|
|
if (verifyBuffer[i] != pageBuffer[i]) {
|
|
writeMatches = 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 (writeMatches) {
|
|
verifySuccess = true;
|
|
break;
|
|
} else if (verifyAttempt < 2) {
|
|
Serial.print("Verifikationsversuch ");
|
|
Serial.print(verifyAttempt + 1);
|
|
Serial.println("/3 fehlgeschlagen, wiederhole...");
|
|
vTaskDelay(30 / portTICK_PERIOD_MS);
|
|
}
|
|
} else {
|
|
Serial.print("Verifikations-Read-Versuch ");
|
|
Serial.print(verifyAttempt + 1);
|
|
Serial.println("/3 fehlgeschlagen");
|
|
if (verifyAttempt < 2) {
|
|
vTaskDelay(30 / portTICK_PERIOD_MS);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!verifySuccess) {
|
|
Serial.println("❌ SCHREIBVORGANG/VERIFIKATION FEHLGESCHLAGEN!");
|
|
free(tlvData);
|
|
return 0;
|
|
} else {
|
|
Serial.println("✓");
|
|
}
|
|
|
|
Serial.print("Seite ");
|
|
Serial.print(pageNumber);
|
|
Serial.print(" ✓: ");
|
|
for (int i = 0; i < 4; i++) {
|
|
if (pageBuffer[i] < 0x10) Serial.print("0");
|
|
Serial.print(pageBuffer[i], HEX);
|
|
Serial.print(" ");
|
|
}
|
|
Serial.println();
|
|
|
|
bytesWritten += bytesToWrite;
|
|
pageNumber++;
|
|
|
|
yield();
|
|
vTaskDelay(10 / portTICK_PERIOD_MS); // Slightly increased delay between page writes
|
|
}
|
|
|
|
free(tlvData);
|
|
|
|
if (bytesWritten < totalBytes) {
|
|
Serial.println("WARNUNG: Nicht alle Daten konnten geschrieben werden!");
|
|
Serial.print("Geschrieben: ");
|
|
Serial.print(bytesWritten);
|
|
Serial.print(" von ");
|
|
Serial.print(totalBytes);
|
|
Serial.println(" Bytes");
|
|
Serial.print("Gestoppt bei Seite: ");
|
|
Serial.println(pageNumber - 1);
|
|
return 0;
|
|
}
|
|
|
|
Serial.println();
|
|
Serial.println("✓ NDEF-Nachricht erfolgreich geschrieben!");
|
|
Serial.print("✓ Tag-Typ: ");Serial.println(tagType);
|
|
Serial.print("✓ Insgesamt ");Serial.print(bytesWritten);Serial.println(" Bytes geschrieben");
|
|
Serial.print("✓ Verwendete Seiten: 4-");Serial.println(pageNumber - 1);
|
|
Serial.print("✓ Speicher-Auslastung: ");
|
|
Serial.print((bytesWritten * 100) / availableUserData);
|
|
Serial.println("%");
|
|
Serial.println("✓ Bestehende Daten wurden überschrieben");
|
|
|
|
// CRITICAL: Allow NFC interface to stabilize after write operation
|
|
Serial.println();
|
|
Serial.println("=== SCHRITT 7: NFC-INTERFACE STABILISIERUNG NACH SCHREIBVORGANG ===");
|
|
Serial.println("Stabilisiere NFC-Interface nach Schreibvorgang...");
|
|
|
|
// Give the tag and interface time to settle after write operation
|
|
vTaskDelay(300 / portTICK_PERIOD_MS); // Increased stabilization time
|
|
|
|
// Test if the interface is still responsive
|
|
uint8_t postWriteTest[4];
|
|
bool interfaceResponsive = false;
|
|
|
|
for (int stabilityAttempt = 0; stabilityAttempt < 5; stabilityAttempt++) {
|
|
Serial.print("Post-write interface test ");
|
|
Serial.print(stabilityAttempt + 1);
|
|
Serial.print("/5... ");
|
|
|
|
if (nfc.ntag2xx_ReadPage(3, postWriteTest)) { // Read capability container
|
|
Serial.println("✓");
|
|
interfaceResponsive = true;
|
|
break;
|
|
} else {
|
|
Serial.println("❌");
|
|
|
|
if (stabilityAttempt < 4) {
|
|
Serial.println("Warte und versuche Interface zu stabilisieren...");
|
|
vTaskDelay(200 / portTICK_PERIOD_MS);
|
|
|
|
// Try to re-establish communication with a simple tag presence check
|
|
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 presence check: ");
|
|
Serial.println(tagStillPresent ? "✓" : "❌");
|
|
|
|
if (!tagStillPresent) {
|
|
Serial.println("Tag wurde während/nach Schreibvorgang entfernt!");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!interfaceResponsive) {
|
|
Serial.println("WARNUNG: NFC-Interface reagiert nach Schreibvorgang nicht mehr stabil");
|
|
Serial.println("Schreibvorgang war erfolgreich, aber Interface benötigt möglicherweise Reset");
|
|
} else {
|
|
Serial.println("✓ NFC-Interface ist nach Schreibvorgang stabil");
|
|
}
|
|
|
|
Serial.println("==================================================================");
|
|
|
|
return 1;
|
|
}
|
|
|
|
bool decodeNdefAndReturnJson(const byte* encodedMessage, String uidString) {
|
|
oledShowProgressBar(1, octoEnabled?5:4, "Reading", "Decoding data");
|
|
|
|
// 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 NDEF message length from TLV
|
|
uint16_t ndefMessageLength = 0;
|
|
int ndefRecordOffset = 0;
|
|
|
|
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 (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("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 = 1 + 1 + payloadLengthBytes + typeLength + idLength;
|
|
|
|
Serial.print("Calculated payload offset: ");
|
|
Serial.println(payloadOffset);
|
|
|
|
// Verify we have enough data
|
|
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 with validation
|
|
uint32_t actualJsonLength = 0;
|
|
for (uint32_t i = 0; i < payloadLength; 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.print("Total nfcJsonData length: ");
|
|
Serial.println(nfcJsonData.length());
|
|
Serial.println("=== DECODED JSON DATA START ===");
|
|
Serial.println(nfcJsonData);
|
|
Serial.println("=== DECODED JSON DATA END ===");
|
|
|
|
// Check if JSON was truncated
|
|
if (nfcJsonData.length() < payloadLength && !nfcJsonData.endsWith("}")) {
|
|
Serial.println("WARNING: JSON payload appears to be truncated!");
|
|
Serial.print("Expected payload length: ");
|
|
Serial.println(payloadLength);
|
|
Serial.print("Actual extracted length: ");
|
|
Serial.println(nfcJsonData.length());
|
|
}
|
|
|
|
// Trim any trailing whitespace or invalid characters
|
|
nfcJsonData.trim();
|
|
|
|
// JSON-Dokument verarbeiten
|
|
JsonDocument doc;
|
|
DeserializationError error = deserializeJson(doc, nfcJsonData);
|
|
if (error)
|
|
{
|
|
nfcJsonData = "";
|
|
Serial.println("Fehler beim Verarbeiten des JSON-Dokuments");
|
|
Serial.print("deserializeJson() failed: ");
|
|
Serial.println(error.f_str());
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// If spoolman is unavailable, there is no point in continuing
|
|
if(spoolmanConnected){
|
|
// Sende die aktualisierten AMS-Daten an alle WebSocket-Clients
|
|
Serial.println("JSON-Dokument erfolgreich verarbeitet");
|
|
Serial.println(doc.as<String>());
|
|
if (doc["sm_id"].is<String>() && doc["sm_id"] != "" && doc["sm_id"] != "0")
|
|
{
|
|
oledShowProgressBar(2, octoEnabled?5:4, "Spool Tag", "Weighing");
|
|
Serial.println("SPOOL-ID gefunden: " + doc["sm_id"].as<String>());
|
|
activeSpoolId = doc["sm_id"].as<String>();
|
|
lastSpoolId = activeSpoolId;
|
|
}
|
|
else if(doc["location"].is<String>() && doc["location"] != "")
|
|
{
|
|
Serial.println("Location Tag found!");
|
|
String location = doc["location"].as<String>();
|
|
if(lastSpoolId != ""){
|
|
updateSpoolLocation(lastSpoolId, location);
|
|
}
|
|
else
|
|
{
|
|
Serial.println("Location update tag scanned without scanning spool before!");
|
|
oledShowProgressBar(1, 1, "Failure", "Scan spool first");
|
|
}
|
|
}
|
|
// Brand Filament not registered to Spoolman
|
|
else if ((!doc["sm_id"].is<String>() || (doc["sm_id"].is<String>() && (doc["sm_id"] == "0" || doc["sm_id"] == "")))
|
|
&& doc["b"].is<String>() && doc["an"].is<String>())
|
|
{
|
|
doc["sm_id"] = "0"; // Ensure sm_id is set to 0
|
|
// If no sm_id is present but the brand is Brand Filament then
|
|
// create a new spool, maybe brand too, in Spoolman
|
|
Serial.println("New Brand Filament Tag found!");
|
|
createBrandFilament(doc, uidString);
|
|
}
|
|
else
|
|
{
|
|
Serial.println("Keine SPOOL-ID gefunden.");
|
|
activeSpoolId = "";
|
|
oledShowProgressBar(1, 1, "Failure", "Unkown tag");
|
|
}
|
|
}else{
|
|
oledShowProgressBar(octoEnabled?5:4, octoEnabled?5:4, "Failure!", "Spoolman unavailable");
|
|
}
|
|
}
|
|
|
|
doc.clear();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool quickSpoolIdCheck(String uidString) {
|
|
// Fast-path: Read NDEF structure to quickly locate and check JSON payload
|
|
// 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 enough pages to cover NDEF header + beginning of payload (pages 4-8 = 20 bytes)
|
|
uint8_t ndefData[20];
|
|
memset(ndefData, 0, 20);
|
|
|
|
for (uint8_t page = 4; page < 9; page++) {
|
|
if (!nfc.ntag2xx_ReadPage(page, ndefData + (page - 4) * 4)) {
|
|
Serial.print("Failed to read page ");
|
|
Serial.println(page);
|
|
return false; // Fall back to full read
|
|
}
|
|
}
|
|
|
|
// Parse NDEF structure to find JSON payload start
|
|
Serial.print("Raw NDEF data (first 20 bytes): ");
|
|
for (int i = 0; i < 20; i++) {
|
|
if (ndefData[i] < 0x10) Serial.print("0");
|
|
Serial.print(ndefData[i], HEX);
|
|
Serial.print(" ");
|
|
}
|
|
Serial.println();
|
|
|
|
// Look for NDEF TLV (0x03) at the beginning
|
|
int tlvOffset = -1;
|
|
for (int i = 0; i < 8; i++) {
|
|
if (ndefData[i] == 0x03) {
|
|
tlvOffset = i;
|
|
Serial.print("Found NDEF TLV at offset: ");
|
|
Serial.println(tlvOffset);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tlvOffset == -1) {
|
|
Serial.println("✗ FAST-PATH: No NDEF TLV found");
|
|
return false;
|
|
}
|
|
|
|
// Parse NDEF record to find JSON payload
|
|
int ndefRecordStart;
|
|
if (ndefData[tlvOffset + 1] == 0xFF) {
|
|
// Extended length format
|
|
ndefRecordStart = tlvOffset + 4;
|
|
} else {
|
|
// Standard length format
|
|
ndefRecordStart = tlvOffset + 2;
|
|
}
|
|
|
|
if (ndefRecordStart >= 20) {
|
|
Serial.println("✗ FAST-PATH: NDEF record starts beyond read data");
|
|
return false;
|
|
}
|
|
|
|
// Parse NDEF record header
|
|
uint8_t recordHeader = ndefData[ndefRecordStart];
|
|
uint8_t typeLength = ndefData[ndefRecordStart + 1];
|
|
|
|
// Calculate payload offset
|
|
uint8_t payloadLengthBytes = (recordHeader & 0x10) ? 1 : 4; // SR flag check
|
|
uint8_t idLength = (recordHeader & 0x08) ? ndefData[ndefRecordStart + 2 + payloadLengthBytes + typeLength] : 0; // IL flag check
|
|
|
|
int payloadOffset = ndefRecordStart + 1 + 1 + payloadLengthBytes + typeLength + idLength;
|
|
|
|
Serial.print("NDEF Record Header: 0x");
|
|
Serial.print(recordHeader, HEX);
|
|
Serial.print(", Type Length: ");
|
|
Serial.print(typeLength);
|
|
Serial.print(", Payload offset: ");
|
|
Serial.println(payloadOffset);
|
|
|
|
// Check if payload starts within our read data
|
|
if (payloadOffset >= 20) {
|
|
Serial.println("✗ FAST-PATH: JSON payload starts beyond quick read data - need more pages");
|
|
|
|
// Read additional pages to get to JSON payload
|
|
uint8_t extraData[16]; // Read 4 more pages
|
|
memset(extraData, 0, 16);
|
|
|
|
for (uint8_t page = 9; page < 13; page++) {
|
|
if (!nfc.ntag2xx_ReadPage(page, extraData + (page - 9) * 4)) {
|
|
Serial.print("Failed to read additional page ");
|
|
Serial.println(page);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Combine data
|
|
uint8_t combinedData[36];
|
|
memcpy(combinedData, ndefData, 20);
|
|
memcpy(combinedData + 20, extraData, 16);
|
|
|
|
// Extract JSON from combined data
|
|
String jsonStart = "";
|
|
int jsonStartPos = payloadOffset;
|
|
for (int i = 0; i < 36 - payloadOffset && i < 30; i++) {
|
|
uint8_t currentByte = combinedData[payloadOffset + i];
|
|
if (currentByte >= 32 && currentByte <= 126) {
|
|
jsonStart += (char)currentByte;
|
|
}
|
|
// Stop at first brace to get just the beginning
|
|
if (currentByte == '{' && i > 0) break;
|
|
}
|
|
|
|
Serial.print("JSON start from extended read: ");
|
|
Serial.println(jsonStart);
|
|
|
|
// Check for sm_id pattern - look for non-zero sm_id values
|
|
if (jsonStart.indexOf("\"sm_id\":\"") >= 0) {
|
|
int smIdStart = jsonStart.indexOf("\"sm_id\":\"") + 9;
|
|
int smIdEnd = jsonStart.indexOf("\"", smIdStart);
|
|
|
|
if (smIdEnd > smIdStart && smIdEnd < jsonStart.length()) {
|
|
String quickSpoolId = jsonStart.substring(smIdStart, smIdEnd);
|
|
Serial.print("Found sm_id in extended read: ");
|
|
Serial.println(quickSpoolId);
|
|
|
|
// Only process if sm_id is not "0" (known spool)
|
|
if (quickSpoolId != "0" && quickSpoolId.length() > 0) {
|
|
Serial.println("✓ FAST-PATH: Known spool detected!");
|
|
|
|
// 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;
|
|
} else {
|
|
Serial.println("✗ FAST-PATH: sm_id is 0 - new brand filament, need full read");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
Serial.println("✗ FAST-PATH: No sm_id pattern in extended read");
|
|
return false;
|
|
}
|
|
|
|
// Extract JSON payload from the available data
|
|
String quickJson = "";
|
|
for (int i = payloadOffset; i < 20 && i < payloadOffset + 15; i++) {
|
|
uint8_t currentByte = ndefData[i];
|
|
if (currentByte >= 32 && currentByte <= 126) {
|
|
quickJson += (char)currentByte;
|
|
}
|
|
}
|
|
|
|
Serial.print("Quick JSON data: ");
|
|
Serial.println(quickJson);
|
|
|
|
// Look for sm_id pattern in the beginning of JSON - check for known vs new spools
|
|
if (quickJson.indexOf("\"sm_id\":\"") >= 0) {
|
|
Serial.println("✓ FAST-PATH: sm_id field found");
|
|
|
|
// Extract sm_id from quick data
|
|
int smIdStart = quickJson.indexOf("\"sm_id\":\"") + 9;
|
|
int smIdEnd = quickJson.indexOf("\"", smIdStart);
|
|
|
|
if (smIdEnd > smIdStart && smIdEnd < quickJson.length()) {
|
|
String quickSpoolId = quickJson.substring(smIdStart, smIdEnd);
|
|
Serial.print("✓ Quick extracted sm_id: ");
|
|
Serial.println(quickSpoolId);
|
|
|
|
// Only process known spools (sm_id != "0") via fast path
|
|
if (quickSpoolId != "0" && quickSpoolId.length() > 0) {
|
|
Serial.println("✓ FAST-PATH: Known spool detected!");
|
|
|
|
// 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;
|
|
} else {
|
|
Serial.println("✗ FAST-PATH: sm_id is 0 - new brand filament, need full read");
|
|
return false; // sm_id="0" means new brand filament, needs full processing
|
|
}
|
|
} else {
|
|
Serial.println("✗ FAST-PATH: Could not extract complete sm_id value");
|
|
return false; // Need full read to get complete sm_id
|
|
}
|
|
}
|
|
|
|
// Check for other patterns that require full read
|
|
if (quickJson.indexOf("\"location\":\"") >= 0) {
|
|
Serial.println("✓ FAST-PATH: Location tag detected");
|
|
return false; // Need full read for location processing
|
|
}
|
|
|
|
if (quickJson.indexOf("\"brand\":\"") >= 0) {
|
|
Serial.println("✓ FAST-PATH: Brand filament detected - may need full processing");
|
|
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;
|
|
|
|
// Gib die erstellte NDEF-Message aus
|
|
Serial.println("Erstelle NDEF-Message...");
|
|
Serial.println(params->payload);
|
|
|
|
nfcReaderState = NFC_WRITING;
|
|
nfcWriteInProgress = true; // Block high-level tag operations during write
|
|
|
|
// 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
|
|
sendNfcData();
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
// Wait 10sec for tag
|
|
uint8_t success = 0;
|
|
String uidString = "";
|
|
for (uint16_t i = 0; i < 20; i++) {
|
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
|
uint8_t uidLength;
|
|
// yield before potentially waiting for 400ms
|
|
yield();
|
|
esp_task_wdt_reset();
|
|
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 400);
|
|
if (success) {
|
|
for (uint8_t i = 0; i < uidLength; i++) {
|
|
//TBD: Rework to remove all the string operations
|
|
uidString += String(uid[i], HEX);
|
|
if (i < uidLength - 1) {
|
|
uidString += ":"; // Optional: Trennzeichen hinzufügen
|
|
}
|
|
}
|
|
foundNfcTag(nullptr, success);
|
|
break;
|
|
}
|
|
|
|
yield();
|
|
esp_task_wdt_reset();
|
|
vTaskDelay(pdMS_TO_TICKS(1));
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
oledShowProgressBar(1, 3, "Write Tag", "Writing");
|
|
|
|
// Schreibe die NDEF-Message auf den Tag
|
|
success = ntag2xx_WriteNDEF(params->payload);
|
|
if (success)
|
|
{
|
|
Serial.println("NDEF-Message erfolgreich auf den Tag geschrieben");
|
|
//oledShowMessage("NFC-Tag written");
|
|
//vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
nfcReaderState = NFC_WRITE_SUCCESS;
|
|
// aktualisieren der Website wenn sich der Status ändert
|
|
sendNfcData();
|
|
pauseBambuMqttTask = false;
|
|
|
|
if(params->tagType){
|
|
// TBD: should this be simplified?
|
|
if (updateSpoolTagId(uidString, params->payload) && params->tagType) {
|
|
|
|
}else{
|
|
// Potentially handle errors
|
|
}
|
|
}else{
|
|
oledShowProgressBar(1, 1, "Write Tag", "Done!");
|
|
}
|
|
|
|
// CRITICAL: Properly stabilize NFC interface after write operation
|
|
Serial.println();
|
|
Serial.println("=== POST-WRITE NFC STABILIZATION ===");
|
|
|
|
// Wait for tag operations to complete
|
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
|
|
|
// Test tag presence and remove detection
|
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
|
|
uint8_t uidLength;
|
|
int tagRemovalChecks = 0;
|
|
|
|
Serial.println("Warte bis Tag entfernt wird...");
|
|
|
|
// Monitor tag presence
|
|
while (tagRemovalChecks < 10) {
|
|
yield();
|
|
esp_task_wdt_reset();
|
|
|
|
bool tagPresent = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500);
|
|
|
|
if (!tagPresent) {
|
|
Serial.println("✓ Tag wurde entfernt - NFC bereit für nächsten Scan");
|
|
break;
|
|
}
|
|
|
|
tagRemovalChecks++;
|
|
Serial.print("Tag noch vorhanden (");
|
|
Serial.print(tagRemovalChecks);
|
|
Serial.println("/10)");
|
|
|
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
|
}
|
|
|
|
if (tagRemovalChecks >= 10) {
|
|
Serial.println("WARNUNG: Tag wurde nicht entfernt - fahre trotzdem fort");
|
|
}
|
|
|
|
// Additional interface stabilization before resuming normal operations
|
|
Serial.println("Stabilisiere NFC-Interface für normale Operationen...");
|
|
vTaskDelay(200 / portTICK_PERIOD_MS);
|
|
|
|
// Test if interface is ready for normal scanning
|
|
uint8_t interfaceTestBuffer[4];
|
|
bool interfaceReady = false;
|
|
|
|
for (int testAttempt = 0; testAttempt < 3; testAttempt++) {
|
|
// Try a simple interface operation (without requiring tag presence)
|
|
Serial.print("Interface readiness test ");
|
|
Serial.print(testAttempt + 1);
|
|
Serial.print("/3... ");
|
|
|
|
// Use a safe read operation that doesn't depend on tag presence
|
|
// This tests if the PN532 chip itself is responsive
|
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
|
if (versiondata != 0) {
|
|
Serial.println("✓");
|
|
interfaceReady = true;
|
|
break;
|
|
} else {
|
|
Serial.println("❌");
|
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
}
|
|
}
|
|
|
|
if (!interfaceReady) {
|
|
Serial.println("WARNUNG: NFC-Interface reagiert nicht - könnte normale Scans beeinträchtigen");
|
|
} else {
|
|
Serial.println("✓ NFC-Interface ist bereit für normale Scans");
|
|
}
|
|
|
|
Serial.println("=========================================");
|
|
|
|
vTaskResume(RfidReaderTask);
|
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
|
}
|
|
else
|
|
{
|
|
Serial.println("Fehler beim Schreiben der NDEF-Message auf den Tag");
|
|
oledShowIcon("failed");
|
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
|
nfcReaderState = NFC_WRITE_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Serial.println("Fehler: Kein Tag zu schreiben gefunden.");
|
|
oledShowProgressBar(1, 1, "Failure!", "No tag found");
|
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
|
nfcReaderState = NFC_IDLE;
|
|
}
|
|
|
|
sendWriteResult(nullptr, success);
|
|
sendNfcData();
|
|
|
|
// Only reset the write protection flag - reading task was never suspended
|
|
nfcWriteInProgress = false; // Re-enable high-level tag operations
|
|
pauseBambuMqttTask = false;
|
|
|
|
free(params->payload);
|
|
delete params;
|
|
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
void startWriteJsonToTag(const bool isSpoolTag, const char* payload) {
|
|
NfcWriteParameterType* parameters = new NfcWriteParameterType();
|
|
parameters->tagType = isSpoolTag;
|
|
parameters->payload = strdup(payload);
|
|
|
|
// Task nicht mehrfach starten
|
|
if (nfcReaderState == NFC_IDLE || nfcReaderState == NFC_READ_ERROR || nfcReaderState == NFC_READ_SUCCESS) {
|
|
oledShowProgressBar(0, 1, "Write Tag", "Place tag now");
|
|
// Erstelle die Task
|
|
xTaskCreate(
|
|
writeJsonToTag, // Task-Funktion
|
|
"WriteJsonToTagTask", // Task-Name
|
|
5115, // Stackgröße in Bytes
|
|
(void*)parameters, // Parameter
|
|
rfidWriteTaskPrio, // Priorität
|
|
NULL // Task-Handle (nicht benötigt)
|
|
);
|
|
}else{
|
|
oledShowProgressBar(0, 1, "FAILURE", "NFC busy!");
|
|
// TBD: Add proper error handling (website)
|
|
}
|
|
}
|
|
|
|
void scanRfidTask(void * parameter) {
|
|
Serial.println("RFID Task gestartet");
|
|
for(;;) {
|
|
// Skip scanning during write operations, but keep NFC interface active
|
|
if (nfcReaderState != NFC_WRITING && !nfcWriteInProgress && !nfcReadingTaskSuspendRequest && !booting)
|
|
{
|
|
nfcReadingTaskSuspendState = false;
|
|
yield();
|
|
|
|
uint8_t success;
|
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
|
uint8_t uidLength;
|
|
|
|
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500);
|
|
|
|
foundNfcTag(nullptr, success);
|
|
|
|
// As long as there is still a tag on the reader, do not try to read it again
|
|
if (success && nfcReaderState == NFC_IDLE)
|
|
{
|
|
// Set the current tag as not processed
|
|
tagProcessed = false;
|
|
|
|
// Display some basic information about the card
|
|
Serial.println("Found an ISO14443A card");
|
|
|
|
nfcReaderState = NFC_READING;
|
|
|
|
oledShowProgressBar(0, octoEnabled?5:4, "Reading", "Detecting tag");
|
|
|
|
// Wait 1 second after tag detection to stabilize connection
|
|
Serial.println("Tag detected, waiting 1 second for stabilization...");
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
// create Tag UID string
|
|
String uidString = "";
|
|
for (uint8_t i = 0; i < uidLength; i++) {
|
|
//TBD: Rework to remove all the string operations
|
|
uidString += String(uid[i], HEX);
|
|
if (i < uidLength - 1) {
|
|
uidString += ":"; // Optional: Trennzeichen hinzufügen
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
// Create a buffer depending on the size of the tag
|
|
uint8_t* data = (uint8_t*)malloc(tagSize);
|
|
memset(data, 0, tagSize);
|
|
|
|
// We probably have an NTAG2xx card (though it could be Ultralight as well)
|
|
Serial.println("Seems to be an NTAG2xx tag (7 byte UID)");
|
|
Serial.print("Tag size: ");
|
|
Serial.print(tagSize);
|
|
Serial.println(" bytes");
|
|
|
|
uint8_t numPages = readTagSize()/4;
|
|
|
|
for (uint8_t i = 4; i < 4+numPages; i++) {
|
|
|
|
if (!nfc.ntag2xx_ReadPage(i, data+(i-4) * 4))
|
|
{
|
|
break; // Stop if reading fails
|
|
}
|
|
|
|
// Check for NDEF message end
|
|
if (data[(i - 4) * 4] == 0xFE)
|
|
{
|
|
Serial.println("Found NDEF message end marker");
|
|
break; // End of NDEF message
|
|
}
|
|
|
|
yield();
|
|
esp_task_wdt_reset();
|
|
// Increased delay to ensure stable reading
|
|
vTaskDelay(pdMS_TO_TICKS(5)); // Increased from 1ms to 5ms
|
|
}
|
|
|
|
Serial.println("Tag reading completed, starting NDEF decode...");
|
|
|
|
if (!decodeNdefAndReturnJson(data, uidString))
|
|
{
|
|
oledShowProgressBar(1, 1, "Failure", "Unknown tag");
|
|
nfcReaderState = NFC_READ_ERROR;
|
|
}
|
|
else
|
|
{
|
|
nfcReaderState = NFC_READ_SUCCESS;
|
|
}
|
|
|
|
free(data);
|
|
}
|
|
else
|
|
{
|
|
oledShowProgressBar(1, 1, "Failure", "Tag read error");
|
|
nfcReaderState = NFC_READ_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//TBD: Show error here?!
|
|
oledShowProgressBar(1, 1, "Failure", "Unkown tag type");
|
|
Serial.println("This doesn't seem to be an NTAG2xx tag (UUID length != 7 bytes)!");
|
|
}
|
|
}
|
|
|
|
if (!success && nfcReaderState != NFC_IDLE && !nfcReadingTaskSuspendRequest)
|
|
{
|
|
nfcReaderState = NFC_IDLE;
|
|
//uidString = "";
|
|
nfcJsonData = "";
|
|
activeSpoolId = "";
|
|
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();
|
|
}
|
|
else
|
|
{
|
|
nfcReadingTaskSuspendState = true;
|
|
|
|
// 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();
|
|
}
|
|
}
|
|
|
|
void startNfc() {
|
|
oledShowProgressBar(5, 7, DISPLAY_BOOT_TEXT, "NFC init");
|
|
nfc.begin(); // Beginne Kommunikation mit RFID Leser
|
|
delay(1000);
|
|
unsigned long versiondata = nfc.getFirmwareVersion(); // Lese Versionsnummer der Firmware aus
|
|
if (! versiondata) { // Wenn keine Antwort kommt
|
|
Serial.println("Kann kein RFID Board finden !"); // Sende Text "Kann kein..." an seriellen Monitor
|
|
oledShowMessage("No RFID Board found");
|
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
|
}
|
|
else {
|
|
Serial.print("Chip PN5 gefunden"); Serial.println((versiondata >> 24) & 0xFF, HEX); // Sende Text und Versionsinfos an seriellen
|
|
Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC); // Monitor, wenn Antwort vom Board kommt
|
|
Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC); //
|
|
|
|
nfc.SAMConfig();
|
|
// Set the max number of retry attempts to read from a card
|
|
// This prevents us from waiting forever for a card, which is
|
|
// the default behaviour of the PN532.
|
|
//nfc.setPassiveActivationRetries(0x7F);
|
|
//nfc.setPassiveActivationRetries(0xFF);
|
|
|
|
BaseType_t result = xTaskCreatePinnedToCore(
|
|
scanRfidTask, /* Function to implement the task */
|
|
"RfidReader", /* Name of the task */
|
|
5115, /* Stack size in words */
|
|
NULL, /* Task input parameter */
|
|
rfidTaskPrio, /* Priority of the task */
|
|
&RfidReaderTask, /* Task handle. */
|
|
rfidTaskCore); /* Core where the task should run */
|
|
|
|
if (result != pdPASS) {
|
|
Serial.println("Fehler beim Erstellen des RFID Tasks");
|
|
} else {
|
|
Serial.println("RFID Task erfolgreich erstellt");
|
|
}
|
|
}
|
|
} |