/
RfidPn5180.cpp
371 lines (337 loc) · 13.9 KB
/
RfidPn5180.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
#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 <esp_task_wdt.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_READCARD 2u
#define RFID_PN5180_NFC14443_STATE_ACTIVE 99u
#define RFID_PN5180_NFC15693_STATE_RESET 3u
#define RFID_PN5180_NFC15693_STATE_SETUPRF 4u
#define RFID_PN5180_NFC15693_STATE_DISABLEPRIVACYMODE 5u
#define RFID_PN5180_NFC15693_STATE_GETINVENTORY 6u
#define RFID_PN5180_NFC15693_STATE_ACTIVE 100u
extern unsigned long Rfid_LastRfidCheckTimestamp;
#ifdef RFID_READER_TYPE_PN5180
static void Rfid_Task(void *parameter);
static TaskHandle_t rfidTaskHandle;
#ifdef PN5180_ENABLE_LPCD
void Rfid_EnableLpcd(void);
bool enabledLpcdShutdown = false; // Indicates if LPCD should be activated as part of the shutdown-process
void Rfid_SetLpcdShutdownStatus(bool lpcdStatus) {
enabledLpcdShutdown = lpcdStatus;
}
bool Rfid_GetLpcdShutdownStatus(void) {
return enabledLpcdShutdown;
}
#endif
void Rfid_Init(void) {
#ifdef PN5180_ENABLE_LPCD
// Check if wakeup-reason was card-detection (PN5180 only)
// This only works if RFID.IRQ is connected to a GPIO and not to a port-expander
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT1) {
Rfid_WakeupCheck();
}
// 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
#if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO)
pinMode(RFID_IRQ, INPUT); // Not necessary for port-expander as for pca9555 all pins are configured as input per default
#endif
#endif
xTaskCreatePinnedToCore(
Rfid_Task, /* Function to implement the task */
"rfid", /* Name of the task */
1536, /* Stack size in words */
NULL, /* Task input parameter */
2 | portPRIVILEGE_BIT, /* Priority of the task */
&rfidTaskHandle, /* Task handle. */
0 /* Core where the task should run */
);
}
void Rfid_Cyclic(void) {
// Not necessary as cyclic stuff performed by task Rfid_Task()
}
void Rfid_Task(void *parameter) {
static PN5180ISO14443 nfc14443(RFID_CS, RFID_BUSY, RFID_RST);
static PN5180ISO15693 nfc15693(RFID_CS, RFID_BUSY, RFID_RST);
uint32_t lastTimeDetected14443 = 0;
uint32_t lastTimeDetected15693 = 0;
#ifdef PAUSE_WHEN_RFID_REMOVED
byte lastValidcardId[cardIdSize];
bool cardAppliedCurrentRun = false;
bool cardAppliedLastRun = false;
#endif
uint8_t stateMachine = RFID_PN5180_STATE_INIT;
static byte cardId[cardIdSize], lastCardId[cardIdSize];
uint8_t uid[10];
// wait until queues are created
while(gRfidCardQueue == NULL){
Log_Println((char *) FPSTR(waitingForTaskQueues), LOGLEVEL_DEBUG);
vTaskDelay(50);
}
for (;;) {
vTaskDelay(portTICK_RATE_MS * 10u);
#ifdef PN5180_ENABLE_LPCD
if (Rfid_GetLpcdShutdownStatus()) {
Rfid_EnableLpcd();
Rfid_SetLpcdShutdownStatus(false); // give feedback that execution is complete
while (true) {
vTaskDelay(portTICK_RATE_MS * 100u); // there's no way back if shutdown was initiated
}
}
#endif
String cardIdString;
bool cardReceived = false;
#ifdef PAUSE_WHEN_RFID_REMOVED
bool sameCardReapplied = false;
#endif
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));
snprintf(Log_Buffer, Log_BufferLength, "%s%d.%d", (char *) F("PN5180 firmware version="), firmwareVersion[1], firmwareVersion[0]);
Log_Println(Log_Buffer, LOGLEVEL_DEBUG);
// 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();
//snprintf(Log_Buffer, Log_BufferLength, "%u", uxTaskGetStackHighWaterMark(NULL));
//Log_Println(Log_Buffer, LOGLEVEL_DEBUG);
} else if (RFID_PN5180_NFC14443_STATE_READCARD == stateMachine) {
if (nfc14443.readCardSerial(uid) >= 4) {
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 >= 1000)) {
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) {
Log_Println((char *) F("disabling privacy-mode successful"), LOGLEVEL_NOTICE);
}
} 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 && System_GetOperationMode() != OPMODE_BLUETOOTH_SINK) { // Card removed => pause
AudioPlayer_TrackControlToQueueSender(PAUSEPLAY);
Log_Println((char *) FPSTR(rfidTagRemoved), LOGLEVEL_NOTICE);
}
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;
continue;
} else if (RFID_PN5180_NFC15693_STATE_ACTIVE == stateMachine) {
stateMachine = RFID_PN5180_NFC15693_STATE_RESET;
continue;
}
}
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, true);
snprintf(Log_Buffer, Log_BufferLength, "(%s) ID: ", (RFID_PN5180_NFC14443_STATE_ACTIVE == stateMachine) ? "ISO-14443" : "ISO-15693");
Log_Print(Log_Buffer, LOGLEVEL_NOTICE, false);
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, false);
}
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 && System_GetOperationMode() != OPMODE_BLUETOOTH_SINK) {
AudioPlayer_TrackControlToQueueSender(PAUSEPLAY); // ... play/pause instead
Log_Println((char *) FPSTR(rfidTagReapplied), LOGLEVEL_NOTICE);
}
}
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 (RFID_PN5180_NFC14443_STATE_ACTIVE == stateMachine) { // If 14443 is active, bypass 15693 as next check (performance)
stateMachine = RFID_PN5180_NFC14443_STATE_RESET;
} else if (RFID_PN5180_NFC15693_STATE_ACTIVE == stateMachine) { // 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) {
#ifdef PN5180_ENABLE_LPCD
Rfid_SetLpcdShutdownStatus(true);
while (Rfid_GetLpcdShutdownStatus()) { // Make sure init of LPCD is complete!
vTaskDelay(portTICK_RATE_MS * 10u);
}
#endif
vTaskDelete(rfidTaskHandle);
}
// Handles activation of LPCD (while shutdown is in progress)
void Rfid_EnableLpcd(void) {
// goto low power card detection mode
#ifdef PN5180_ENABLE_LPCD
static PN5180 nfc(RFID_CS, RFID_BUSY, RFID_RST);
nfc.begin();
nfc.reset();
// show PN5180 reader version
uint8_t firmwareVersion[2];
nfc.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion));
snprintf(Log_Buffer, Log_BufferLength, "%s%d.%d", (char *) F("PN5180 firmware version="), firmwareVersion[1], firmwareVersion[0]);
Log_Println(Log_Buffer, LOGLEVEL_DEBUG);
// 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) {
Log_Println((char *) F("This PN5180 firmware does not work with LPCD! use firmware >= 4.0"), LOGLEVEL_ERROR);
return;
}
Log_Println((char *) F("prepare low power card detection..."), LOGLEVEL_NOTICE);
uint8_t irqConfig = 0b0000000; // Set IRQ active low + clear IRQ-register
nfc.writeEEprom(IRQ_PIN_CONFIG, &irqConfig, 1);
/*nfc.readEEprom(IRQ_PIN_CONFIG, &irqConfig, 1);
Serial.print(F("IRQ_PIN_CONFIG=0x"));
Serial.println(irqConfig, HEX);*/
nfc.prepareLPCD();
Log_Println((char *) F("PN5180 IRQ PIN: "), LOGLEVEL_NOTICE);
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)) {
Log_Println((char *) F("switch to low power card detection: success"), LOGLEVEL_NOTICE);
// configure wakeup pin for deep-sleep wake-up, use ext1
#if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO)
esp_sleep_enable_ext1_wakeup((1ULL << (RFID_IRQ)), ESP_EXT1_WAKEUP_ALL_LOW);
#endif
// 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 {
Log_Println((char *) F("switchToLPCD failed"), LOGLEVEL_ERROR);
}
#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
// 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
#if (RFID_IRQ >= 0 && RFID_IRQ <= MAX_GPIO)
pinMode(RFID_IRQ, INPUT);
#endif
static PN5180ISO14443 nfc14443(RFID_CS, RFID_BUSY, RFID_RST);
nfc14443.begin();
nfc14443.reset();
// enable RF field
nfc14443.setupRF();
if (!nfc14443.isCardPresent()) {
nfc14443.reset();
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_ALL_LOW);
// 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 {
Log_Println((char *) F("switchToLPCD failed"), LOGLEVEL_ERROR);
}
}
nfc14443.end();
#endif
}
#endif