Skip to content

Commit 1fad9cd

Browse files
fhirschmannclaude
andcommitted
feat: detect RFID tag removal via consecutive miss counter
Replace the 2.5 s wall-clock removal timeout with a counter of consecutive failed read attempts (10). Real removal is detected in ~200-400 ms while single ghost misses and wall-clock gaps caused by task starvation under load no longer trigger phantom removal events. Bridged gaps are logged at DEBUG level to allow tuning the threshold. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 7be5254 commit 1fad9cd

1 file changed

Lines changed: 28 additions & 4 deletions

File tree

‎src/RfidPn5180.cpp‎

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,19 @@ void RfidPn5180_TaskReset(void) {
119119
rfidTaskResetRequested = true;
120120
}
121121

122+
// Number of consecutive failed read attempts before a card is considered removed.
123+
// Counting attempts instead of wall-clock time keeps removal detection fast
124+
// (~200-400 ms at the usual polling rate) while staying immune to single ghost
125+
// misses and to wall-clock gaps caused by task starvation under load.
126+
#define RFID_CARD_REMOVAL_MISS_THRESHOLD 10u
127+
122128
void RfidPn5180_Task(void *parameter) {
123129
static PN5180ISO14443 nfc14443(RFID_CS, RFID_BUSY, RFID_RST);
124130
static PN5180ISO15693 nfc15693(RFID_CS, RFID_BUSY, RFID_RST);
125131
uint32_t lastTimeDetected14443 = 0;
126132
uint32_t lastTimeDetected15693 = 0;
133+
uint8_t misses14443 = 0;
134+
uint8_t misses15693 = 0;
127135
bool cardAppliedCurrentRun = false;
128136
bool cardAppliedLastRun = false;
129137
static byte cardId[cardIdSize], lastCardId[cardIdSize];
@@ -160,6 +168,8 @@ void RfidPn5180_Task(void *parameter) {
160168
// Ensure we don't trigger a removal event during reset
161169
lastTimeDetected14443 = millis();
162170
lastTimeDetected15693 = millis();
171+
misses14443 = 0;
172+
misses15693 = 0;
163173
rfidTaskResetRequested = false;
164174
stateMachine = RFID_PN5180_NFC14443_STATE_RESET;
165175
}
@@ -196,14 +206,21 @@ void RfidPn5180_Task(void *parameter) {
196206
if (nfc14443.readCardSerial(uid) >= 4) {
197207
cardReceived = true;
198208
stateMachine = RFID_PN5180_NFC14443_STATE_ACTIVE;
209+
if (misses14443 > 0) {
210+
// helps tuning RFID_CARD_REMOVAL_MISS_THRESHOLD: how long do phantom dropouts really last?
211+
Log_Printf(LOGLEVEL_DEBUG, "ISO-14443: read gap of %lu ms bridged after %u missed reads", millis() - lastTimeDetected14443, misses14443);
212+
misses14443 = 0;
213+
}
199214
lastTimeDetected14443 = millis();
200215
cardAppliedCurrentRun = true;
201216
} else {
202217
// Reset to dummy-value if no card is there
203218
// Necessary to differentiate between "card is still applied" and "card is re-applied again after removal"
204-
// lastTimeDetected14443 is used to prevent "new card detection with old card" with single events where no card was detected
205-
if (!lastTimeDetected14443 || (millis() - lastTimeDetected14443 >= 2500)) {
219+
// A card is only considered removed after several consecutive failed read attempts,
220+
// so single ghost misses don't trigger a removal event.
221+
if (!lastTimeDetected14443 || (++misses14443 >= RFID_CARD_REMOVAL_MISS_THRESHOLD)) {
206222
lastTimeDetected14443 = 0;
223+
misses14443 = 0;
207224
cardAppliedCurrentRun = false;
208225
for (uint8_t i = 0; i < cardIdSize; i++) {
209226
lastCardId[i] = 0;
@@ -236,12 +253,19 @@ void RfidPn5180_Task(void *parameter) {
236253
if (rc == ISO15693_EC_OK) {
237254
cardReceived = true;
238255
stateMachine = RFID_PN5180_NFC15693_STATE_ACTIVE;
256+
if (misses15693 > 0) {
257+
// helps tuning RFID_CARD_REMOVAL_MISS_THRESHOLD: how long do phantom dropouts really last?
258+
Log_Printf(LOGLEVEL_DEBUG, "ISO-15693: read gap of %lu ms bridged after %u missed reads", millis() - lastTimeDetected15693, misses15693);
259+
misses15693 = 0;
260+
}
239261
lastTimeDetected15693 = millis();
240262
cardAppliedCurrentRun = true;
241263
} else {
242-
// lastTimeDetected15693 is used to prevent "new card detection with old card" with single events where no card was detected
243-
if (!lastTimeDetected15693 || (millis() - lastTimeDetected15693 >= 2500)) {
264+
// A card is only considered removed after several consecutive failed read attempts,
265+
// so single ghost misses don't trigger a removal event.
266+
if (!lastTimeDetected15693 || (++misses15693 >= RFID_CARD_REMOVAL_MISS_THRESHOLD)) {
244267
lastTimeDetected15693 = 0;
268+
misses15693 = 0;
245269
cardAppliedCurrentRun = false;
246270
for (uint8_t i = 0; i < cardIdSize; i++) {
247271
lastCardId[i] = 0;

0 commit comments

Comments
 (0)