#include "nfc.h" #include #include #include #include "config.h" #include "website.h" #include "api.h" #include "esp_task_wdt.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 spoolId = ""; String nfcJsonData = ""; volatile bool pauseBambuMqttTask = false; volatile uint8_t hasReadRfidTag = 0; // 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* version = doc["version"]; const char* protocol = doc["protocol"]; 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(version); Serial.println(protocol); 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()); } } 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; } uint8_t ntag2xx_WriteNDEF(const char *payload) { /* if (!formatNdefTag()) { Serial.println("Fehler beim Formatieren des NDEF-Tags."); hasReadRfidTag = 2; return 0; } */ uint8_t tagSize = 240; // 144 bytes is maximum for NTAG213 Serial.print("Tag Size: ");Serial.println(tagSize); uint8_t pageBuffer[4] = {0, 0, 0, 0}; Serial.println("Beginne mit dem Schreiben der NDEF-Nachricht..."); // Figure out how long the string is uint8_t len = strlen(payload); Serial.print("Länge der Payload: "); Serial.println(len); Serial.print("Payload: ");Serial.println(payload); // Setup the record header // See NFCForum-TS-Type-2-Tag_1.1.pdf for details uint8_t pageHeader[21] = { /* NDEF Message TLV - JSON Record */ 0x03, /* Tag Field (0x03 = NDEF Message) */ (uint8_t)(len+3+16), /* Payload Length (including NDEF header) */ 0xD2, /* NDEF Record Header (TNF=0x2:MIME Media + SR + ME + MB) */ 0x10, /* Type Length for the record type indicator */ (uint8_t)(len), /* Payload len */ 'a', 'p', 'p', 'l', 'i', 'c', 'a', 't', 'i', 'o', 'n', '/', 'j', 's', 'o', 'n' }; // Make sure the URI payload will fit in dataLen (include 0xFE trailer) if ((len < 1) || (len + 1 > (tagSize - sizeof(pageHeader)))) { Serial.println(); Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!"); Serial.println("Fehler: Die Nutzlast passt nicht in die Datenlänge."); Serial.println("!!!!!!!!!!!!!!!!!!!!!!!!"); Serial.println(); return 0; } //Serial.println(); //Serial.print("Header Size: ");Serial.println(sizeof(pageHeader)); // Kombiniere Header und Payload int totalSize = sizeof(pageHeader) + len; uint8_t* combinedData = (uint8_t*) malloc(totalSize); if (combinedData == NULL) { Serial.println("Fehler: Nicht genug Speicher vorhanden."); return 0; } // Überprüfe die Kombination von Header und Payload /* Serial.print("Header: "); for (int i = 0; i < sizeof(pageHeader); i++) { Serial.print(pageHeader[i], HEX); Serial.print(" "); } Serial.println(); Serial.print("Payload: "); for (int i = 0; i < len; i++) { Serial.print(payload[i], HEX); Serial.print(" "); } Serial.println(); */ // Kombiniere Header und Payload memcpy(combinedData, pageHeader, sizeof(pageHeader)); memcpy(&combinedData[sizeof(pageHeader)], payload, len); // Überprüfe die Kombination von Header und Payload /* Serial.print("Kombinierte Daten: "); for (int i = 0; i < totalSize; i++) { Serial.print(combinedData[i], HEX); Serial.print(" "); } Serial.println(); */ // Schreibe die Seiten uint8_t a = 0; uint8_t i = 0; while (totalSize > 0) { memset(pageBuffer, 0, 4); int bytesToWrite = (totalSize < 4) ? totalSize : 4; memcpy(pageBuffer, combinedData + a, bytesToWrite); // Überprüfe die Schreibung der Seiten /* Serial.print("Seite "); Serial.print(i); Serial.print(": "); for (int j = 0; j < bytesToWrite; j++) { Serial.print(pageBuffer[j], HEX); Serial.print(" "); } Serial.println(); */ uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID uint8_t uidLength; nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500); //Serial.print("Schreibe Seite: ");Serial.println(i); if (!(nfc.ntag2xx_WritePage(4+i, pageBuffer))) { Serial.println("Fehler beim Schreiben der Seite."); free(combinedData); return 0; } //Serial.print("Seite geschrieben: ");Serial.println(i); yield(); //esp_task_wdt_reset(); i++; a += 4; totalSize -= bytesToWrite; } // Ensure the NDEF message is properly terminated memset(pageBuffer, 0, 4); pageBuffer[0] = 0xFE; // NDEF record footer if (!(nfc.ntag2xx_WritePage(4+i, pageBuffer))) { Serial.println("Fehler beim Schreiben des End-Bits."); free(combinedData); return 0; } Serial.println("NDEF-Nachricht erfolgreich geschrieben."); free(combinedData); return 1; } bool decodeNdefAndReturnJson(const byte* encodedMessage) { byte typeLength = encodedMessage[3]; byte payloadLength = encodedMessage[4]; nfcJsonData = ""; for (int i = 2; i < payloadLength+2; i++) { nfcJsonData += (char)encodedMessage[3 + typeLength + i]; } // JSON-Dokument verarbeiten JsonDocument doc; // Passen Sie die Größe an den JSON-Inhalt an 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 { // Sende die aktualisierten AMS-Daten an alle WebSocket-Clients Serial.println("JSON-Dokument erfolgreich verarbeitet"); Serial.println(doc.as()); if (doc["sm_id"] != "") { Serial.println("SPOOL-ID gefunden: " + doc["sm_id"].as()); spoolId = doc["sm_id"].as(); } else { Serial.println("Keine SPOOL-ID gefunden."); spoolId = ""; oledShowMessage("Unknown Spool"); vTaskDelay(2000 / portTICK_PERIOD_MS); } } return true; } void writeJsonToTag(void *parameter) { const char* payload = (const char*)parameter; // Gib die erstellte NDEF-Message aus Serial.println("Erstelle NDEF-Message..."); hasReadRfidTag = 3; vTaskSuspend(RfidReaderTask); //pauseBambuMqttTask = true; // aktualisieren der Website wenn sich der Status ändert sendNfcData(nullptr); // 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; success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500); if (success) { for (uint8_t i = 0; i < uidLength; i++) { uidString += String(uid[i], HEX); if (i < uidLength - 1) { uidString += ":"; // Optional: Trennzeichen hinzufügen } } foundNfcTag(nullptr, success); break; } if (i == 0) oledShowMessage("Waiting for NFC-Tag"); yield(); esp_task_wdt_reset(); vTaskDelay(pdMS_TO_TICKS(1)); } if (success) { oledShowIcon("transfer"); // Schreibe die NDEF-Message auf den Tag success = ntag2xx_WriteNDEF(payload); if (success) { Serial.println("NDEF-Message erfolgreich auf den Tag geschrieben"); //oledShowMessage("NFC-Tag written"); oledShowIcon("success"); vTaskDelay(2000 / portTICK_PERIOD_MS); hasReadRfidTag = 5; // aktualisieren der Website wenn sich der Status ändert sendNfcData(nullptr); vTaskResume(RfidReaderTask); pauseBambuMqttTask = false; updateSpoolTagId(uidString, payload); } else { Serial.println("Fehler beim Schreiben der NDEF-Message auf den Tag"); oledShowIcon("failed"); vTaskDelay(2000 / portTICK_PERIOD_MS); hasReadRfidTag = 4; } } else { Serial.println("Fehler: Kein Tag zu schreiben gefunden."); oledShowMessage("No NFC-Tag found"); vTaskDelay(2000 / portTICK_PERIOD_MS); hasReadRfidTag = 0; } sendWriteResult(nullptr, success); sendNfcData(nullptr); vTaskResume(RfidReaderTask); pauseBambuMqttTask = false; vTaskDelete(NULL); } void startWriteJsonToTag(const char* payload) { char* payloadCopy = strdup(payload); // Erstelle die Task xTaskCreate( writeJsonToTag, // Task-Funktion "WriteJsonToTagTask", // Task-Name 4096, // Stackgröße in Bytes (void*)payloadCopy, // Parameter rfidWriteTaskPrio, // Priorität NULL // Task-Handle (nicht benötigt) ); } void scanRfidTask(void * parameter) { Serial.println("RFID Task gestartet"); for(;;) { // Wenn geschrieben wird Schleife aussetzen if (hasReadRfidTag != 3) { 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, 1000); foundNfcTag(nullptr, success); if (success && hasReadRfidTag != 1) { // Display some basic information about the card Serial.println("Found an ISO14443A card"); hasReadRfidTag = 6; oledShowIcon("transfer"); vTaskDelay(1000 / portTICK_PERIOD_MS); if (uidLength == 7) { uint8_t data[256]; // We probably have an NTAG2xx card (though it could be Ultralight as well) Serial.println("Seems to be an NTAG2xx tag (7 byte UID)"); for (uint8_t i = 0; i < 45; i++) { /* if (i < uidLength) { uidString += String(uid[i], HEX); if (i < uidLength - 1) { uidString += ":"; // Optional: Trennzeichen hinzufügen } } */ if (!nfc.mifareclassic_ReadDataBlock(i, data + (i - 4) * 4)) { break; // Stop if reading fails } // Check for NDEF message end if (data[(i - 4) * 4] == 0xFE) { break; // End of NDEF message } yield(); esp_task_wdt_reset(); vTaskDelay(pdMS_TO_TICKS(1)); } if (!decodeNdefAndReturnJson(data)) { oledShowMessage("NFC-Tag unknown"); vTaskDelay(2000 / portTICK_PERIOD_MS); hasReadRfidTag = 2; } else { hasReadRfidTag = 1; } } else { Serial.println("This doesn't seem to be an NTAG2xx tag (UUID length != 7 bytes)!"); } } if (!success && hasReadRfidTag > 0) { hasReadRfidTag = 0; //uidString = ""; nfcJsonData = ""; Serial.println("Tag entfernt"); oledShowWeight(0); } // aktualisieren der Website wenn sich der Status ändert sendNfcData(nullptr); } yield(); } } void startNfc() { 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 //delay(5000); //ESP.restart(); oledShowMessage("No RFID Board found"); delay(2000); } 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 */ 10000, /* 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"); } } }