You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
13 KiB
296 lines
13 KiB
#include <Arduino.h>
|
|
#include <freertos/task.h>
|
|
#include <esp_task_wdt.h>
|
|
#include "settings.h"
|
|
#include "Rfid.h"
|
|
#include "Log.h"
|
|
#include "MemX.h"
|
|
#include "Queues.h"
|
|
#include "System.h"
|
|
#include "Port.h"
|
|
#include "AudioPlayer.h"
|
|
|
|
#ifdef RFID_READER_TYPE_PN5180
|
|
#include <PN5180.h>
|
|
#include <PN5180ISO14443.h>
|
|
#include <PN5180ISO15693.h>
|
|
#endif
|
|
|
|
#define RFID_PN5180_STATE_INIT 0u
|
|
|
|
#define RFID_PN5180_NFC14443_STATE_RESET 1u
|
|
#define RFID_PN5180_NFC14443_STATE_SETUPRF 2u
|
|
#define RFID_PN5180_NFC14443_STATE_READCARD 3u
|
|
#define RFID_PN5180_NFC14443_STATE_ACTIVE 99u
|
|
|
|
#define RFID_PN5180_NFC15693_STATE_RESET 4u
|
|
#define RFID_PN5180_NFC15693_STATE_SETUPRF 5u
|
|
#define RFID_PN5180_NFC15693_STATE_DISABLEPRIVACYMODE 6u
|
|
#define RFID_PN5180_NFC15693_STATE_GETINVENTORY 7u
|
|
#define RFID_PN5180_NFC15693_STATE_ACTIVE 100u
|
|
|
|
extern unsigned long Rfid_LastRfidCheckTimestamp;
|
|
|
|
#ifdef RFID_READER_TYPE_PN5180
|
|
static void Rfid_Read(void);
|
|
|
|
void Rfid_Init(void) {
|
|
#ifdef PN5180_ENABLE_LPCD
|
|
// disable pin hold from deep sleep
|
|
gpio_deep_sleep_hold_dis();
|
|
gpio_hold_dis(gpio_num_t(RFID_CS)); // NSS
|
|
gpio_hold_dis(gpio_num_t(RFID_RST)); // RST
|
|
pinMode(RFID_IRQ, INPUT);
|
|
#endif
|
|
}
|
|
|
|
void Rfid_Cyclic(void) {
|
|
Rfid_Read();
|
|
vTaskDelay(5u);
|
|
}
|
|
|
|
void Rfid_Read(void) {
|
|
static PN5180ISO14443 nfc14443(RFID_CS, RFID_BUSY, RFID_RST);
|
|
static PN5180ISO15693 nfc15693(RFID_CS, RFID_BUSY, RFID_RST);
|
|
static uint32_t lastTimeDetected14443 = 0;
|
|
static uint32_t lastTimeDetected15693 = 0;
|
|
#ifdef PAUSE_WHEN_RFID_REMOVED
|
|
static byte lastValidcardId[cardIdSize];
|
|
static bool cardAppliedCurrentRun = false;
|
|
static bool cardAppliedLastRun = false;
|
|
bool sameCardReapplied = false;
|
|
#endif
|
|
static uint8_t stateMachine = RFID_PN5180_STATE_INIT;
|
|
static byte cardId[cardIdSize], lastCardId[cardIdSize];
|
|
uint8_t uid[10];
|
|
String cardIdString;
|
|
bool cardReceived = false;
|
|
|
|
if (RFID_PN5180_STATE_INIT == stateMachine) {
|
|
nfc14443.begin();
|
|
nfc14443.reset();
|
|
// show PN5180 reader version
|
|
uint8_t firmwareVersion[2];
|
|
nfc14443.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion));
|
|
Serial.print(F("Firmware version="));
|
|
Serial.print(firmwareVersion[1]);
|
|
Serial.print(".");
|
|
Serial.println(firmwareVersion[0]);
|
|
|
|
// activate RF field
|
|
delay(4u);
|
|
Log_Println((char *) FPSTR(rfidScannerReady), LOGLEVEL_DEBUG);
|
|
|
|
// 1. check for an ISO-14443 card
|
|
} else if (RFID_PN5180_NFC14443_STATE_RESET == stateMachine) {
|
|
nfc14443.reset();
|
|
} else if (RFID_PN5180_NFC14443_STATE_SETUPRF == stateMachine) {
|
|
nfc14443.setupRF();
|
|
} else if (RFID_PN5180_NFC14443_STATE_READCARD == stateMachine) {
|
|
if (nfc14443.readCardSerial(uid) >= 4u) {
|
|
cardReceived = true;
|
|
stateMachine = RFID_PN5180_NFC14443_STATE_ACTIVE;
|
|
lastTimeDetected14443 = millis();
|
|
#ifdef PAUSE_WHEN_RFID_REMOVED
|
|
cardAppliedCurrentRun = true;
|
|
#endif
|
|
} else {
|
|
// Reset to dummy-value if no card is there
|
|
// Necessary to differentiate between "card is still applied" and "card is re-applied again after removal"
|
|
// lastTimeDetected14443 is used to prevent "new card detection with old card" with single events where no card was detected
|
|
if (!lastTimeDetected14443 || (millis() - lastTimeDetected14443 >= 400)) {
|
|
lastTimeDetected14443 = 0;
|
|
#ifdef PAUSE_WHEN_RFID_REMOVED
|
|
cardAppliedCurrentRun = false;
|
|
#endif
|
|
for (uint8_t i=0; i<cardIdSize; i++) {
|
|
lastCardId[i] = 0;
|
|
}
|
|
} else {
|
|
stateMachine = RFID_PN5180_NFC14443_STATE_ACTIVE; // Still consider first event as "active"
|
|
}
|
|
}
|
|
|
|
// 2. check for an ISO-15693 card
|
|
} else if (RFID_PN5180_NFC15693_STATE_RESET == stateMachine) {
|
|
nfc15693.reset();
|
|
} else if (RFID_PN5180_NFC15693_STATE_SETUPRF == stateMachine) {
|
|
nfc15693.setupRF();
|
|
} else if (RFID_PN5180_NFC15693_STATE_DISABLEPRIVACYMODE == stateMachine) {
|
|
// check for ICODE-SLIX2 password protected tag
|
|
// put your privacy password here, e.g.:
|
|
// https://de.ifixit.com/Antworten/Ansehen/513422/nfc+Chips+f%C3%BCr+tonies+kaufen
|
|
uint8_t password[] = {0x01, 0x02, 0x03, 0x04};
|
|
ISO15693ErrorCode myrc = nfc15693.disablePrivacyMode(password);
|
|
if (ISO15693_EC_OK == myrc) {
|
|
Serial.println(F("disabling privacy-mode successful"));
|
|
}
|
|
} else if (RFID_PN5180_NFC15693_STATE_GETINVENTORY == stateMachine) {
|
|
// try to read ISO15693 inventory
|
|
ISO15693ErrorCode rc = nfc15693.getInventory(uid);
|
|
if (rc == ISO15693_EC_OK) {
|
|
cardReceived = true;
|
|
stateMachine = RFID_PN5180_NFC15693_STATE_ACTIVE;
|
|
lastTimeDetected15693 = millis();
|
|
#ifdef PAUSE_WHEN_RFID_REMOVED
|
|
cardAppliedCurrentRun = true;
|
|
#endif
|
|
} else {
|
|
// lastTimeDetected15693 is used to prevent "new card detection with old card" with single events where no card was detected
|
|
if (!lastTimeDetected15693 || (millis() - lastTimeDetected15693 >= 400)) {
|
|
lastTimeDetected15693 = 0;
|
|
#ifdef PAUSE_WHEN_RFID_REMOVED
|
|
cardAppliedCurrentRun = false;
|
|
#endif
|
|
for (uint8_t i=0; i<cardIdSize; i++) {
|
|
lastCardId[i] = 0;
|
|
}
|
|
} else {
|
|
stateMachine = RFID_PN5180_NFC15693_STATE_ACTIVE;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef PAUSE_WHEN_RFID_REMOVED
|
|
if (!cardAppliedCurrentRun && cardAppliedLastRun && !gPlayProperties.pausePlay) { // Card removed => pause
|
|
AudioPlayer_TrackControlToQueueSender(PAUSEPLAY);
|
|
}
|
|
cardAppliedLastRun = cardAppliedCurrentRun;
|
|
#endif
|
|
|
|
// send card to queue
|
|
if (cardReceived) {
|
|
memcpy(cardId, uid, cardIdSize);
|
|
|
|
// check for different card id
|
|
if (memcmp((const void *)cardId, (const void *)lastCardId, sizeof(cardId)) == 0) {
|
|
// reset state machine
|
|
if (RFID_PN5180_NFC14443_STATE_ACTIVE == stateMachine) {
|
|
stateMachine = RFID_PN5180_NFC14443_STATE_RESET;
|
|
return;
|
|
} else if (RFID_PN5180_NFC15693_STATE_ACTIVE == stateMachine) {
|
|
stateMachine = RFID_PN5180_NFC15693_STATE_RESET;
|
|
return;
|
|
}
|
|
}
|
|
|
|
memcpy(lastCardId, cardId, cardIdSize);
|
|
|
|
#ifdef PAUSE_WHEN_RFID_REMOVED
|
|
if (memcmp((const void *)lastValidcardId, (const void *)cardId, sizeof(cardId)) == 0) {
|
|
sameCardReapplied = true;
|
|
}
|
|
#endif
|
|
|
|
Log_Print((char *) FPSTR(rfidTagDetected), LOGLEVEL_NOTICE);
|
|
snprintf(Log_Buffer, Log_BufferLength, "(%s) ID: ", (RFID_PN5180_NFC14443_STATE_ACTIVE == stateMachine) ? "ISO-14443" : "ISO-15693");
|
|
Log_Print(Log_Buffer, LOGLEVEL_NOTICE);
|
|
|
|
for (uint8_t i = 0u; i < cardIdSize; i++) {
|
|
snprintf(Log_Buffer, Log_BufferLength, "%02x%s", cardId[i], (i < cardIdSize - 1u) ? "-" : "\n");
|
|
Log_Print(Log_Buffer, LOGLEVEL_NOTICE);
|
|
}
|
|
|
|
for (uint8_t i = 0u; i < cardIdSize; i++) {
|
|
char num[4];
|
|
snprintf(num, sizeof(num), "%03d", cardId[i]);
|
|
cardIdString += num;
|
|
}
|
|
|
|
#ifdef PAUSE_WHEN_RFID_REMOVED
|
|
if (!sameCardReapplied) { // Don't allow to send card to queue if it's the same card again...
|
|
xQueueSend(gRfidCardQueue, cardIdString.c_str(), 0);
|
|
} else {
|
|
// If pause-button was pressed while card was not applied, playback could be active. If so: don't pause when card is reapplied again as the desired functionality would be reversed in this case.
|
|
if (gPlayProperties.pausePlay) {
|
|
AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); // ... play/pause instead
|
|
}
|
|
}
|
|
memcpy(lastValidcardId, uid, cardIdSize);
|
|
#else
|
|
xQueueSend(gRfidCardQueue, cardIdString.c_str(), 0); // If PAUSE_WHEN_RFID_REMOVED isn't active, every card-apply leads to new playlist-generation
|
|
#endif
|
|
}
|
|
|
|
if (stateMachine == RFID_PN5180_NFC14443_STATE_ACTIVE) { // If 14443 is active, bypass 15693 as next check (performance)
|
|
stateMachine = RFID_PN5180_NFC14443_STATE_RESET;
|
|
} else if (stateMachine == RFID_PN5180_NFC15693_STATE_ACTIVE) { // If 15693 is active, bypass 14443 as next check (performance)
|
|
stateMachine = RFID_PN5180_NFC15693_STATE_RESET;
|
|
} else {
|
|
stateMachine++;
|
|
if (stateMachine > RFID_PN5180_NFC15693_STATE_GETINVENTORY) {
|
|
stateMachine = RFID_PN5180_NFC14443_STATE_RESET;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Rfid_Exit(void) {
|
|
// goto low power card detection mode
|
|
#ifdef PN5180_ENABLE_LPCD
|
|
static PN5180 nfc(RFID_CS, RFID_BUSY, RFID_RST);
|
|
nfc.begin();
|
|
// show PN5180 reader version
|
|
uint8_t firmwareVersion[2];
|
|
nfc.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion));
|
|
Serial.print(F("Firmware version="));
|
|
Serial.print(firmwareVersion[1]);
|
|
Serial.print(".");
|
|
Serial.println(firmwareVersion[0]);
|
|
// check firmware version: PN5180 firmware < 4.0 has several bugs preventing the LPCD mode
|
|
// you can flash latest firmware with this project: https://github.com/abidxraihan/PN5180_Updater_ESP32
|
|
if (firmwareVersion[1] < 4) {
|
|
Serial.println(F("This PN5180 firmware does not work with LPCD! use firmware >= 4.0"));
|
|
return;
|
|
}
|
|
Serial.println(F("prepare low power card detection..."));
|
|
nfc.prepareLPCD();
|
|
nfc.clearIRQStatus(0xffffffff);
|
|
Serial.print(F("PN5180 IRQ PIN: "));
|
|
Serial.println(Port_Read(RFID_IRQ));
|
|
// turn on LPCD
|
|
uint16_t wakeupCounterInMs = 0x3FF; // must be in the range of 0x0 - 0xA82. max wake-up time is 2960 ms.
|
|
if (nfc.switchToLPCD(wakeupCounterInMs)) {
|
|
Serial.println(F("switch to low power card detection: success"));
|
|
// configure wakeup pin for deep-sleep wake-up, use ext1
|
|
esp_sleep_enable_ext1_wakeup((1ULL << (RFID_IRQ)), ESP_EXT1_WAKEUP_ANY_HIGH);
|
|
// freeze pin states in deep sleep
|
|
gpio_hold_en(gpio_num_t(RFID_CS)); // CS/NSS
|
|
gpio_hold_en(gpio_num_t(RFID_RST)); // RST
|
|
gpio_deep_sleep_hold_en();
|
|
} else {
|
|
Serial.println(F("switchToLPCD failed"));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// wake up from LPCD, check card is present. This works only for ISO-14443 compatible cards
|
|
void Rfid_WakeupCheck(void) {
|
|
#ifdef PN5180_ENABLE_LPCD
|
|
static PN5180ISO14443 nfc14443(RFID_CS, RFID_BUSY, RFID_RST);
|
|
nfc14443.begin();
|
|
nfc14443.reset();
|
|
nfc14443.setupRF();
|
|
if (!nfc14443.isCardPresent()) {
|
|
nfc14443.clearIRQStatus(0xffffffff);
|
|
Serial.print(F("Logic-level at PN5180's IRQ-PIN: "));
|
|
Serial.println(Port_Read(RFID_IRQ));
|
|
// turn on LPCD
|
|
uint16_t wakeupCounterInMs = 0x3FF; // needs to be in the range of 0x0 - 0xA82. max wake-up time is 2960 ms.
|
|
if (nfc14443.switchToLPCD(wakeupCounterInMs)) {
|
|
Log_Println((char *) FPSTR(lowPowerCardSuccess), LOGLEVEL_INFO);
|
|
// configure wakeup pin for deep-sleep wake-up, use ext1
|
|
esp_sleep_enable_ext1_wakeup((1ULL << (RFID_IRQ)), ESP_EXT1_WAKEUP_ANY_HIGH);
|
|
// freeze pin states in deep sleep
|
|
gpio_hold_en(gpio_num_t(RFID_CS)); // CS/NSS
|
|
gpio_hold_en(gpio_num_t(RFID_RST)); // RST
|
|
gpio_deep_sleep_hold_en();
|
|
Log_Println((char *) FPSTR(wakeUpRfidNoIso14443), LOGLEVEL_ERROR);
|
|
esp_deep_sleep_start();
|
|
} else {
|
|
Serial.println(F("switchToLPCD failed"));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif
|