1
0
Fork 0

RFID: functional tag reading

Add a new class to handle the RFID module and associated data
in order to track active tags.
Update main with RFID initialization and a minimal usage to
check it is working as expected.
This commit is contained in:
Teo-CD 2023-09-10 20:28:27 +01:00
parent 07654829ed
commit ec2c71b0be
3 changed files with 219 additions and 4 deletions

91
include/RFID.h Normal file
View file

@ -0,0 +1,91 @@
//
// Created by trotfunky on 10/09/23.
//
#ifndef JIN_BARBAPAPA_RFID_H
#define JIN_BARBAPAPA_RFID_H
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <Metro.h>
#include <MFRC522v2.h>
#include <MFRC522DriverPinSimple.h>
#include <MFRC522DriverSPI.h>
#include "Pinout.h"
/***
* Linked list containing the uids of the tags and the corresponding IDs.
*/
struct uidNode {
MFRC522Constants::Uid uid{};
uidNode* next = nullptr;
// IDs should be positive integers < 127 as the sign is used for direction.
int8_t tag_ID = 0;
};
class RFID {
public:
RFID() : comData{}, sd(SD) {};
void init();
/***
* Check if any new tags are present or have left. Only one event is reported
* at a time, another call would be needed to get eventual concurrent events.
* This updates the respective lists and returns the ID with the direction
* of the change.
* @return 0 if no change, +ID if new tag detected, -ID if the tag left.
*/
int8_t checkTags();
private:
/* Used for "encrypted" communication with the tags. */
static MFRC522Constants::MIFARE_Key defaultKey;
static constexpr int maxTags = 2;
int currentActiveTags = 0;
/*
* The linked list tracking active tags.
* It is statically allocated so that the memory footprint is constant.
*/
uidNode activeTagsArray[maxTags];
uidNode* activeTags = nullptr;
uidNode* nextFreeTagSlot = activeTagsArray;
MFRC522DriverPinSimple driverPin{pin_NFC1_CS};
MFRC522DriverSPI driverSpi{driverPin};
MFRC522 mfrc{driverSpi};
/*
* Array used to read and write blocks to the tags. Blocks are 16 bytes but
* during reads a two-bytes CRC is added.
*/
byte comData[18];
SDClass &sd;
Metro checkGoneTimer{250};
/***
* Add a tag to the static linked list.
* @return The new node, or nullptr if all nodes are allocated.
*/
uidNode* addActiveTag(const MFRC522Constants::Uid &newTagUid);
/***
* Remove goneNode from the list and optionally update its predecessor.
* @param goneNode Node to remove from the list.
* @param previousNode Node to update, can be nullptr if goneNode is the head.
*/
void removeActiveTag(uidNode* goneNode, uidNode* previousNode);
/**
* Read block at blockADdr from tagUid and return if the read succeeded or not.
* The read block will be in comData.
* @param tagUid Uid of the tag to be read.
* @param blockAddr Address of the block to be read.
* @return True if read succeeded, false otherwise.
*/
bool readBlock(MFRC522Constants::Uid &tagUid, byte blockAddr);
};
#endif //JIN_BARBAPAPA_RFID_H

116
src/RFID.cpp Normal file
View file

@ -0,0 +1,116 @@
//
// Created by Teo-CD on 10/09/23.
//
#include "RFID.h"
MFRC522Constants::MIFARE_Key RFID::defaultKey = {0xFF,0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
void RFID::init() {
// Create and set up a static linked list to manage active tags.
for (int i = 0; i < maxTags - 1; i++) {
activeTagsArray[i].next = &activeTagsArray[i+1];
}
mfrc.PCD_Init();
}
int8_t RFID::checkTags() {
// First check if some tags are gone. Check for new tags later.
if (currentActiveTags && checkGoneTimer.check()) {
uidNode* previousNode = nullptr;
uidNode* node = activeTags;
while (node) {
byte comSize = sizeof(comData);
mfrc.uid = node->uid;
mfrc.PICC_WakeupA(comData, &comSize);
if (mfrc.PICC_Select(&node->uid, node->uid.size) == MFRC522Constants::STATUS_OK) {
// If we get a response : the tag is still here, halt it again and continue.
mfrc.PICC_HaltA();
previousNode = node;
node = node->next;
// Serial.printf("UID 0x%lX is still present\n", *(uint32_t *)previousNode->uid.uidByte);
} else {
// Serial.printf("UID 0x%lX is gone\n", *(uint32_t *)node->uid.uidByte);
// If we don't, assume the tag is gone and remove it from the list.
removeActiveTag(node, previousNode);
// Return the negative ID to signal it has gone.
// If other tags are gone we can check on the next loop.
return -node->tag_ID;
}
}
}
// If we still have room, check for new tags and read their serials.
if ( currentActiveTags >= maxTags ||
!mfrc.PICC_IsNewCardPresent() ||
!mfrc.PICC_ReadCardSerial()) {
return 0;
}
// Assume we have a new tag.
uidNode* newTag = addActiveTag(mfrc.uid);
// Tag ID is put in a specific block, which can be read after from comData.
if ( !newTag ) {
return 0;
}
// If the read fails, we cannot use this tag anyway so remove it from the list.
if (!readBlock(newTag->uid, 0x11) ) {
removeActiveTag(newTag, nullptr);
return 0;
}
// TODO: ID check ?
newTag->tag_ID = comData[0];
return newTag->tag_ID;
}
uidNode* RFID::addActiveTag(const MFRC522Constants::Uid &newTag) {
if (!nextFreeTagSlot) {
return nullptr;
}
uidNode* temp;
temp = nextFreeTagSlot->next;
// Move the top of the free list to the in use list.
nextFreeTagSlot->next = activeTags;
activeTags = nextFreeTagSlot;
activeTags->uid = newTag;
// Set the top of the free list to the next element, which we saved above.
nextFreeTagSlot = temp;
currentActiveTags++;
return activeTags;
}
void RFID::removeActiveTag(uidNode* goneNode, uidNode* previousNode) {
// Handle the edge case where we remove the last active tag.
if (previousNode) {
previousNode->next = goneNode->next;
} else {
activeTags = goneNode->next;
}
goneNode->next = nextFreeTagSlot;
nextFreeTagSlot = goneNode;
currentActiveTags--;
}
bool RFID::readBlock(MFRC522Constants::Uid &uidToRead, byte blockAddr) {
if (mfrc.PCD_Authenticate(
MFRC522Constants::PICC_Command::PICC_CMD_MF_AUTH_KEY_A,
blockAddr, (&defaultKey),&uidToRead)!= MFRC522Constants::STATUS_OK) {
Serial.println("Failed to authenticate");
return false;
} else {
byte size = sizeof(comData);
mfrc.MIFARE_Read(blockAddr, comData, &size);
// Serial.printf("Read block : 0x%lX\n", *(uint32_t *)comData);
}
// Needed otherwise no new communications can happen.
mfrc.PCD_StopCrypto1();
// No need to keep the tag active.
mfrc.PICC_HaltA();
return true;
}

View file

@ -1,11 +1,9 @@
#include <Arduino.h> #include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <MFRC522v2.h>
#include "Pinout.h" #include "Pinout.h"
#include "RFID.h"
__attribute__((noreturn)) int main() { __attribute__((noreturn)) int main() {
pinMode(pin_DBG_LED_1, OUTPUT); pinMode(pin_DBG_LED_1, OUTPUT);
pinMode(pin_DBG_LED_2, OUTPUT); pinMode(pin_DBG_LED_2, OUTPUT);
@ -41,9 +39,19 @@ __attribute__((noreturn)) int main() {
Serial.println("# System is powered up, running set-up."); Serial.println("# System is powered up, running set-up.");
/* TODO: Setups once module structure is up. */ /* TODO: Setups once module structure is up. */
RFID rfid;
digitalWrite(pin_NFC1_RST, HIGH);
rfid.init();
/* Main loop */ /* Main loop */
while (true) { while (true) {
int8_t tagID;
tagID = rfid.checkTags();
if (tagID) {
Serial.printf("Check tag result : %d\n", tagID);
}
delay(100);
} }
} }