Compare commits
No commits in common. "5618f52a0e444866ac6617b06333fe0a8b72fae3" and "a438cb13d4f9f53fc9dc68a89f69968fba0b7290" have entirely different histories.
5618f52a0e
...
a438cb13d4
6 changed files with 11 additions and 257 deletions
55
README.md
55
README.md
|
@ -216,61 +216,6 @@ Octet 1
|
||||||
`D`: bit 7, 1 si enlevé, 0 sinon
|
`D`: bit 7, 1 si enlevé, 0 sinon
|
||||||
`C`: bit 6, 1 si personnage, 0 si année
|
`C`: bit 6, 1 si personnage, 0 si année
|
||||||
|
|
||||||
### Requête d'information pour la programmation de tag
|
|
||||||
|
|
||||||
**En-tête** : `?`
|
|
||||||
**Longueur** : 0 octets
|
|
||||||
**Description** : Message **vide** envoyé du logiciel vers l'objet pour
|
|
||||||
demander les informations complètes qui permettront de programmer les tags.
|
|
||||||
Il attend une réponse de l'objet, décrit dans la catégorie suivante.
|
|
||||||
|
|
||||||
### Réponse d'information pour la programmation de tag
|
|
||||||
|
|
||||||
**En-tête** : `!`
|
|
||||||
**Longueur** : 1 + 5*n octets, n le nombre de figurines présentes (>=0)
|
|
||||||
**Description** : Message de réponse à la requête d'information pour la programmation
|
|
||||||
des tags.
|
|
||||||
Le premier octet est fixé et indique le nombre de figurines présentes, et donc
|
|
||||||
le nombre d'entrées dans le message.
|
|
||||||
Ensuite, chaque entrée est constituée de l'ID actuel, sur un octet, puis de l'UID
|
|
||||||
du tag, sur quatre octets.
|
|
||||||
C'est l'UID qui est utilisé dans la demande de programmation pour sélectionner le tag.
|
|
||||||
|
|
||||||
#### Schéma
|
|
||||||
|
|
||||||
```
|
|
||||||
│Optional, N records
|
|
||||||
┌─┼────┬──┬────┬──┐
|
|
||||||
│N│UID1│I1│UID2│I2│...
|
|
||||||
└─┴────┴──┴────┴──┘
|
|
||||||
0 1 5 6 10 11 - Octets
|
|
||||||
```
|
|
||||||
`N` : Nombre de tags présents, 1 octet
|
|
||||||
`UIDn` : UID du tag n, 4 octets
|
|
||||||
`In` : ID du tag n, 1 octet
|
|
||||||
|
|
||||||
### Message de programmation de tag
|
|
||||||
|
|
||||||
**En-tête** : `=`
|
|
||||||
**Longueur** : 5 octets
|
|
||||||
**Description** : Message envoyé par le logiciel à l'objet, permet de changer
|
|
||||||
(programmer) l'ID stocké dans un tag.
|
|
||||||
Le contenu est formaté de façon similaire à la réponse d'information :
|
|
||||||
l'UID du tag à programmer, sur quatre octets, puis le nouvel identifiant du tag,
|
|
||||||
sur un octet.
|
|
||||||
On ne programme qu'un tag à la fois.
|
|
||||||
|
|
||||||
#### Schéma
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────┬────┐
|
|
||||||
│ UID │ ID │
|
|
||||||
└─────┴────┘
|
|
||||||
0 4 5 - Octets
|
|
||||||
```
|
|
||||||
`UID` : UID du tag à programmer, 4 octets
|
|
||||||
`ID` : Nouvel ID à programmer, 1 octet
|
|
||||||
|
|
||||||
### Message informatif
|
### Message informatif
|
||||||
|
|
||||||
**En-tête** : `#`
|
**En-tête** : `#`
|
||||||
|
|
|
@ -13,43 +13,8 @@
|
||||||
* functions for the fixed protocols.
|
* functions for the fixed protocols.
|
||||||
*/
|
*/
|
||||||
namespace Com {
|
namespace Com {
|
||||||
enum ReceivedMessage {
|
|
||||||
NO_MESSAGE,
|
|
||||||
TAG_INFO_REQUEST,
|
|
||||||
TAG_PROGRAMMING,
|
|
||||||
INVALID_MESSAGE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Struct used for tag info responses and tag programming.
|
|
||||||
* Would be 8 bytes if not packed due to padding.
|
|
||||||
*/
|
|
||||||
struct __attribute__((packed)) TagInfoRecord {
|
|
||||||
uint32_t uid;
|
|
||||||
uint8_t figId;
|
|
||||||
};
|
|
||||||
|
|
||||||
void sendFigUpdate(int8_t event);
|
void sendFigUpdate(int8_t event);
|
||||||
void sendComment(const char message[62], ...);
|
void sendComment(const char message[62], ...);
|
||||||
/**
|
|
||||||
* Send the response to the tag info request.
|
|
||||||
* The TagInfoRecord buffer needs to be properly filled through getTagRecords().
|
|
||||||
* @param tagCount The amount of tags that are present in the response.
|
|
||||||
*/
|
|
||||||
void sendTagInfo(uint8_t tagCount);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Pointer to a buffer of TagInfoRecords
|
|
||||||
*/
|
|
||||||
TagInfoRecord* getTagRecords();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for any incoming message and handle it if needed, returning the
|
|
||||||
* kind of message received if known, no message if there was nothing to read
|
|
||||||
* and invalid message otherwise.
|
|
||||||
* @return Kind of message received.
|
|
||||||
*/
|
|
||||||
ReceivedMessage receiveMessage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //JIN_BARBAPAPA_COM_H
|
#endif //JIN_BARBAPAPA_COM_H
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include <MFRC522DriverPinSimple.h>
|
#include <MFRC522DriverPinSimple.h>
|
||||||
#include <MFRC522DriverSPI.h>
|
#include <MFRC522DriverSPI.h>
|
||||||
|
|
||||||
#include "Com.h"
|
|
||||||
#include "IDs.h"
|
#include "IDs.h"
|
||||||
#include "Pinout.h"
|
#include "Pinout.h"
|
||||||
|
|
||||||
|
@ -31,8 +30,6 @@ struct uidNode {
|
||||||
|
|
||||||
class RFID {
|
class RFID {
|
||||||
public:
|
public:
|
||||||
static constexpr int maxTags = 2;
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Use the main SPI port and NFC chip select by default, but allow choosing
|
* Use the main SPI port and NFC chip select by default, but allow choosing
|
||||||
* an alternate chip select and/or SPI bus if needed to allow multiple
|
* an alternate chip select and/or SPI bus if needed to allow multiple
|
||||||
|
@ -51,26 +48,11 @@ public:
|
||||||
* @return 0 if no change, ID if new tag detected, ID & sign bit if the tag left.
|
* @return 0 if no change, ID if new tag detected, ID & sign bit if the tag left.
|
||||||
*/
|
*/
|
||||||
int8_t checkTags();
|
int8_t checkTags();
|
||||||
|
|
||||||
/***
|
|
||||||
* Populate an already allocated array of sufficient size to fit
|
|
||||||
* maxTags number of TagInfoRecords.
|
|
||||||
* @param tagData Pointer to an array of size maxTags*sizeof(Com::TagInfoRecord)
|
|
||||||
* @return Number of tags actually put in the array.
|
|
||||||
*/
|
|
||||||
uint8_t gatherTagInfo(Com::TagInfoRecord* tagData);
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Change the ID stored in a tag so that it matches tagToProgram.
|
|
||||||
* @param tagToProgram Pointer to an existing struct with the data to program.
|
|
||||||
* @return True if the programming succeeded.
|
|
||||||
*/
|
|
||||||
bool programTag(Com::TagInfoRecord* tagToProgram);
|
|
||||||
private:
|
private:
|
||||||
static const byte tagIdBlock = 0x11;
|
|
||||||
/* Used for "encrypted" communication with the tags. */
|
/* Used for "encrypted" communication with the tags. */
|
||||||
static MFRC522Constants::MIFARE_Key defaultKey;
|
static MFRC522Constants::MIFARE_Key defaultKey;
|
||||||
static int currentActiveTags;
|
static constexpr int maxTags = 2;
|
||||||
|
int currentActiveTags = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The linked list tracking active tags.
|
* The linked list tracking active tags.
|
||||||
|
@ -108,22 +90,11 @@ private:
|
||||||
/**
|
/**
|
||||||
* Read block at blockADdr from tagUid and return if the read succeeded or not.
|
* Read block at blockADdr from tagUid and return if the read succeeded or not.
|
||||||
* The read block will be in comData.
|
* The read block will be in comData.
|
||||||
* The tag needs to be already woken up.
|
|
||||||
* @param tagUid Uid of the tag to be read.
|
* @param tagUid Uid of the tag to be read.
|
||||||
* @param blockAddr Address of the block to be read.
|
* @param blockAddr Address of the block to be read.
|
||||||
* @return True if read succeeded, false otherwise.
|
* @return True if read succeeded, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool readBlock(MFRC522Constants::Uid &tagUid, byte blockAddr);
|
bool readBlock(MFRC522Constants::Uid &tagUid, byte blockAddr);
|
||||||
|
|
||||||
/**
|
|
||||||
* Write data to tagUid at blockAddr and return if the write succeeded or not.
|
|
||||||
* The tag needs to be already woken up.
|
|
||||||
* @param tagUid Uid of the tag to write to.
|
|
||||||
* @param blockAddr Address of the block to write to.
|
|
||||||
* @param data Byte to write.
|
|
||||||
* @return True if write succeeded, false otherwise.
|
|
||||||
*/
|
|
||||||
bool writeBlock(MFRC522Constants::Uid &tagUid, byte blockAddr, uint8_t data);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //JIN_BARBAPAPA_RFID_H
|
#endif //JIN_BARBAPAPA_RFID_H
|
||||||
|
|
59
src/Com.cpp
59
src/Com.cpp
|
@ -3,12 +3,9 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "Com.h"
|
#include "Com.h"
|
||||||
#include "RFID.h"
|
|
||||||
|
|
||||||
namespace Com {
|
namespace Com {
|
||||||
byte buffer[64];
|
byte buffer[64];
|
||||||
TagInfoRecord records[RFID::maxTags] = {};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will flush buffer through either HID or Serial depending on build
|
* Will flush buffer through either HID or Serial depending on build
|
||||||
* options.
|
* options.
|
||||||
|
@ -22,7 +19,7 @@ namespace Com {
|
||||||
Serial.write((const char*)buffer);
|
Serial.write((const char*)buffer);
|
||||||
#endif
|
#endif
|
||||||
/* Clear the buffer. */
|
/* Clear the buffer. */
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendFigUpdate(int8_t event) {
|
void sendFigUpdate(int8_t event) {
|
||||||
|
@ -39,58 +36,4 @@ namespace Com {
|
||||||
va_end(args);
|
va_end(args);
|
||||||
flushBuffer();
|
flushBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendTagInfo(uint8_t tagCount) {
|
|
||||||
buffer[0] = '!';
|
|
||||||
buffer[1] = tagCount;
|
|
||||||
memcpy(buffer + 2, records, sizeof(TagInfoRecord)*tagCount);
|
|
||||||
flushBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
TagInfoRecord* getTagRecords() {
|
|
||||||
return records;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool dataAvailable() {
|
|
||||||
#ifdef USB_RAWHID
|
|
||||||
return usb_rawhid_available();
|
|
||||||
#else
|
|
||||||
/* Serial is used for debug, do not care about message length. */
|
|
||||||
return Serial.available();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void receiveData() {
|
|
||||||
memset(buffer, 0, sizeof(buffer));
|
|
||||||
#ifdef USB_RAWHID
|
|
||||||
/* We know we have data, don't need to set a timeout. */
|
|
||||||
usb_rawhid_recv(buffer, 0);
|
|
||||||
#else
|
|
||||||
/* Could lead to incomplete messages, but should be OK on Teensy. */
|
|
||||||
Serial.readBytes(buffer, Serial.available());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
ReceivedMessage receiveMessage() {
|
|
||||||
if (!dataAvailable())
|
|
||||||
return NO_MESSAGE;
|
|
||||||
receiveData();
|
|
||||||
|
|
||||||
ReceivedMessage messageType;
|
|
||||||
switch (buffer[0]) {
|
|
||||||
case '?':
|
|
||||||
messageType = TAG_INFO_REQUEST;
|
|
||||||
break;
|
|
||||||
case '=':
|
|
||||||
messageType = TAG_PROGRAMMING;
|
|
||||||
/* Make the record available to the rest of the code. */
|
|
||||||
memset(records, 0, sizeof(records));
|
|
||||||
memcpy(records, buffer + 1, sizeof(TagInfoRecord));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
messageType = INVALID_MESSAGE;
|
|
||||||
Serial.printf("Invalid header received : %c\n", buffer[0]);
|
|
||||||
}
|
|
||||||
return messageType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
74
src/RFID.cpp
74
src/RFID.cpp
|
@ -4,11 +4,7 @@
|
||||||
|
|
||||||
#include "RFID.h"
|
#include "RFID.h"
|
||||||
|
|
||||||
static_assert(RFID::maxTags * sizeof(Com::TagInfoRecord) <= 62,
|
|
||||||
"RFID::maxTags too high, protocol cannot support it.\n");
|
|
||||||
|
|
||||||
MFRC522Constants::MIFARE_Key RFID::defaultKey = {0xFF,0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
MFRC522Constants::MIFARE_Key RFID::defaultKey = {0xFF,0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
int RFID::currentActiveTags = 0;
|
|
||||||
|
|
||||||
void RFID::init() {
|
void RFID::init() {
|
||||||
// Create and set up a static linked list to manage active tags.
|
// Create and set up a static linked list to manage active tags.
|
||||||
|
@ -62,47 +58,15 @@ int8_t RFID::checkTags() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// If the read fails, we cannot use this tag anyway so remove it from the list.
|
// If the read fails, we cannot use this tag anyway so remove it from the list.
|
||||||
if (!readBlock(newTag->uid, tagIdBlock) ) {
|
if (!readBlock(newTag->uid, 0x11) ) {
|
||||||
removeActiveTag(newTag, nullptr);
|
removeActiveTag(newTag, nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Don' t check the ID, otherwise we cannot program the tag.
|
// TODO: ID check ?
|
||||||
newTag->tag_ID = comData[0];
|
newTag->tag_ID = comData[0];
|
||||||
return newTag->tag_ID;
|
return newTag->tag_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t RFID::gatherTagInfo(Com::TagInfoRecord *tagData) {
|
|
||||||
int tagCount = 0;
|
|
||||||
for (uidNode* node = activeTags; node; node = node->next) {
|
|
||||||
// The protocol does not support UIDs other than 4 bytes, so assume it
|
|
||||||
// is the case here directly.
|
|
||||||
tagData[tagCount].uid = *(uint32_t*)(node->uid.uidByte);
|
|
||||||
tagData[tagCount].figId = node->tag_ID;
|
|
||||||
tagCount++;
|
|
||||||
}
|
|
||||||
return tagCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RFID::programTag(Com::TagInfoRecord *tagToProgram) {
|
|
||||||
|
|
||||||
byte comSize = sizeof(comData);
|
|
||||||
|
|
||||||
mfrc.uid.size = 4;
|
|
||||||
*(uint32_t*)(mfrc.uid.uidByte) = tagToProgram->uid;
|
|
||||||
mfrc.PICC_WakeupA(comData, &comSize);
|
|
||||||
if (mfrc.PICC_Select(&mfrc.uid, mfrc.uid.size) != MFRC522Constants::STATUS_OK) {
|
|
||||||
Serial.println("Failed to wakeup for programming. Is tag still there ?\n");
|
|
||||||
mfrc.PICC_HaltA();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!writeBlock(mfrc.uid, tagIdBlock, tagToProgram->figId)) {
|
|
||||||
Serial.println("Failed to program tag.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uidNode* RFID::addActiveTag(const MFRC522Constants::Uid &newTag) {
|
uidNode* RFID::addActiveTag(const MFRC522Constants::Uid &newTag) {
|
||||||
if (!nextFreeTagSlot) {
|
if (!nextFreeTagSlot) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -137,40 +101,16 @@ bool RFID::readBlock(MFRC522Constants::Uid &uidToRead, byte blockAddr) {
|
||||||
if (mfrc.PCD_Authenticate(
|
if (mfrc.PCD_Authenticate(
|
||||||
MFRC522Constants::PICC_Command::PICC_CMD_MF_AUTH_KEY_A,
|
MFRC522Constants::PICC_Command::PICC_CMD_MF_AUTH_KEY_A,
|
||||||
blockAddr, (&defaultKey),&uidToRead)!= MFRC522Constants::STATUS_OK) {
|
blockAddr, (&defaultKey),&uidToRead)!= MFRC522Constants::STATUS_OK) {
|
||||||
Serial.println("readBlock: Failed to authenticate");
|
Serial.println("Failed to authenticate");
|
||||||
mfrc.PICC_HaltA();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
byte size = sizeof(comData);
|
byte size = sizeof(comData);
|
||||||
MFRC522::StatusCode status = mfrc.MIFARE_Read(blockAddr, comData, &size);
|
mfrc.MIFARE_Read(blockAddr, comData, &size);
|
||||||
// Serial.printf("Read block : 0x%lX\n", *(uint32_t *)comData);
|
// Serial.printf("Read block : 0x%lX\n", *(uint32_t *)comData);
|
||||||
|
}
|
||||||
// Needed otherwise no new communications can happen.
|
// Needed otherwise no new communications can happen.
|
||||||
mfrc.PCD_StopCrypto1();
|
mfrc.PCD_StopCrypto1();
|
||||||
// No need to keep the tag active.
|
// No need to keep the tag active.
|
||||||
mfrc.PICC_HaltA();
|
mfrc.PICC_HaltA();
|
||||||
return status == MFRC522Constants::STATUS_OK;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
bool RFID::writeBlock(MFRC522Constants::Uid &uidToRead, byte blockAddr, uint8_t data) {
|
|
||||||
if (mfrc.PCD_Authenticate(
|
|
||||||
MFRC522Constants::PICC_Command::PICC_CMD_MF_AUTH_KEY_A,
|
|
||||||
blockAddr, (&defaultKey),&uidToRead)!= MFRC522Constants::STATUS_OK) {
|
|
||||||
Serial.println("writeBlock: Failed to authenticate");
|
|
||||||
mfrc.PICC_HaltA();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte size = sizeof(comData);
|
|
||||||
for (byte& bufferByte: comData)
|
|
||||||
bufferByte = 0;
|
|
||||||
|
|
||||||
*comData = data;
|
|
||||||
|
|
||||||
MFRC522::StatusCode status = mfrc.MIFARE_Write(blockAddr, comData, size);
|
|
||||||
// Needed otherwise no new communications can happen.
|
|
||||||
mfrc.PCD_StopCrypto1();
|
|
||||||
// No need to keep the tag active.
|
|
||||||
mfrc.PICC_HaltA();
|
|
||||||
return status == MFRC522Constants::STATUS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
10
src/main.cpp
10
src/main.cpp
|
@ -77,16 +77,6 @@ __attribute__((noreturn)) int main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Com::ReceivedMessage message = Com::receiveMessage();
|
|
||||||
if (message == Com::TAG_INFO_REQUEST) {
|
|
||||||
uint8_t tagCount = rfid.gatherTagInfo(Com::getTagRecords());
|
|
||||||
Com::sendTagInfo(tagCount);
|
|
||||||
} else if (message == Com::TAG_PROGRAMMING) {
|
|
||||||
if (!rfid.programTag(Com::getTagRecords())) {
|
|
||||||
Com::sendComment("Tag programming failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Drop delay, WFE+timer interrupt(s) ? */
|
/* TODO: Drop delay, WFE+timer interrupt(s) ? */
|
||||||
delay(25);
|
delay(25);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue