Чуть правленные исходники v3.11 1.11: изменен делитель тактирования spi + частота кварца для мастер станции
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
#ifndef SPORTIDUINO_DEBUG_H
|
||||
#define SPORTIDUINO_DEBUG_H
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_PRINTLN(x) Serial.println(x)
|
||||
#define DEBUG_PRINT(x) Serial.print(x)
|
||||
#define DEBUG_PRINTLN_FORMAT(x, format) Serial.println(x, format)
|
||||
#define DEBUG_PRINT_FORMAT(x, format) Serial.print(x, format)
|
||||
#else
|
||||
#define DEBUG_PRINTLN(x)
|
||||
#define DEBUG_PRINT(x)
|
||||
#define DEBUG_PRINTLN_FORMAT(x, format)
|
||||
#define DEBUG_PRINT_FORMAT(x, format)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,532 @@
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "debug.h"
|
||||
#include "rfid.h"
|
||||
|
||||
void Rfid::init(uint8_t ssPin, uint8_t rstPin, uint8_t newAntennaGain) {
|
||||
rfidSsPin = ssPin;
|
||||
rfidRstPin = rstPin;
|
||||
antennaGain = constrain(newAntennaGain, MIN_ANTENNA_GAIN, MAX_ANTENNA_GAIN);
|
||||
memset(authPwd.pass, 0xFF, 4);
|
||||
memset(authPwd.pack, 0, 2);
|
||||
}
|
||||
|
||||
void Rfid::clearLastCardUid() {
|
||||
memset(&lastCardUid, 0, sizeof(lastCardUid));
|
||||
}
|
||||
|
||||
void Rfid::setAntennaGain(uint8_t newAntennaGain) {
|
||||
antennaGain = constrain(newAntennaGain, MIN_ANTENNA_GAIN, MAX_ANTENNA_GAIN);
|
||||
}
|
||||
|
||||
void Rfid::setAuthPassword(uint8_t* password) {
|
||||
if(!password) {
|
||||
return;
|
||||
}
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
authPwd.pass[i] = password[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Rfid::begin(uint8_t newAntennaGain) {
|
||||
if(newAntennaGain) {
|
||||
antennaGain = newAntennaGain;
|
||||
}
|
||||
cardType = CardType::UNKNOWN;
|
||||
authenticated = false;
|
||||
|
||||
SPI.begin();
|
||||
mfrc522.PCD_Init(rfidSsPin, rfidRstPin);
|
||||
mfrc522.PCD_AntennaOff();
|
||||
mfrc522.PCD_SetAntennaGain(antennaGain<<4);
|
||||
mfrc522.PCD_AntennaOn();
|
||||
|
||||
delay(5);
|
||||
|
||||
if(!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
|
||||
clearLastCardUid();
|
||||
return;
|
||||
}
|
||||
|
||||
auto piccType = MFRC522::PICC_GetType(mfrc522.uid.sak);
|
||||
switch(piccType) {
|
||||
case MFRC522::PICC_TYPE_MIFARE_MINI:
|
||||
cardType = CardType::MIFARE_MINI;
|
||||
return;
|
||||
case MFRC522::PICC_TYPE_MIFARE_1K:
|
||||
cardType = CardType::MIFARE_1K;
|
||||
return;
|
||||
case MFRC522::PICC_TYPE_MIFARE_4K:
|
||||
cardType = CardType::MIFARE_4K;
|
||||
return;
|
||||
case MFRC522::PICC_TYPE_MIFARE_UL: {
|
||||
byte pageData[18];
|
||||
byte dataSize = sizeof(pageData);
|
||||
if(ntagCard4PagesRead(3, pageData, &dataSize)) {
|
||||
switch(pageData[2]) {
|
||||
case 0x12:
|
||||
cardType = CardType::NTAG213;
|
||||
return;
|
||||
case 0x3e:
|
||||
cardType = CardType::NTAG215;
|
||||
return;
|
||||
case 0x6d:
|
||||
cardType = CardType::NTAG216;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
cardType = CardType::UNKNOWN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Rfid::end() {
|
||||
if(isCardDetected()) {
|
||||
memcpy(&lastCardUid, &mfrc522.uid, sizeof(lastCardUid));
|
||||
}
|
||||
|
||||
mfrc522.PICC_HaltA();
|
||||
mfrc522.PCD_StopCrypto1();
|
||||
SPI.end();
|
||||
digitalWrite(rfidRstPin, LOW);
|
||||
}
|
||||
|
||||
bool Rfid::isCardDetected() {
|
||||
if(cardType != CardType::UNKNOWN) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Rfid::isNewCardDetected() {
|
||||
if(isCardDetected()) {
|
||||
for(uint8_t i = 0; i < mfrc522.uid.size; i++) {
|
||||
if(lastCardUid.uidByte[i] != mfrc522.uid.uidByte[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTLN("Same UID");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MFRC522::MIFARE_Key defaultMifareKey = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
bool Rfid::mifareCardPageRead(uint8_t pageAdr, byte *data, byte *size) {
|
||||
// data size should be at least 18 bytes!
|
||||
|
||||
if(pageAdr < 3 || *size < 18) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte blockAddr = pageAdr-3 + ((pageAdr-3)/3);
|
||||
byte trailerBlock = blockAddr + (3-blockAddr%4);
|
||||
|
||||
auto status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &defaultMifareKey, &(mfrc522.uid));
|
||||
|
||||
if(status != MFRC522::STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
status = mfrc522.MIFARE_Read(blockAddr, data, size);
|
||||
|
||||
if(status != MFRC522::STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rfid::mifareCardPageWrite(uint8_t pageAdr, byte *data, byte size) {
|
||||
// data size should be 16 bytes!
|
||||
|
||||
if(pageAdr < 3 || size < 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte blockAddr = pageAdr-3 + ((pageAdr-3)/3);
|
||||
byte trailerBlock = blockAddr + (3-blockAddr%4);
|
||||
|
||||
auto status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &defaultMifareKey, &(mfrc522.uid));
|
||||
|
||||
if(status != MFRC522::STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
status = mfrc522.MIFARE_Write(blockAddr, data, size);
|
||||
|
||||
if(status != MFRC522::STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rfid::ntagSetPassword(NtagAuthPassword *password, bool readAndWrite, uint8_t negAuthAttemptsLim, uint8_t startPage) {
|
||||
if(negAuthAttemptsLim > 7) {
|
||||
negAuthAttemptsLim = 7;
|
||||
}
|
||||
|
||||
uint8_t maxPage = getCardMaxPage();
|
||||
if(!ntagCardPageWrite(maxPage + PAGE_PWD_OFFSET, password->pass, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t packPageData[4] = {password->pack[0], password->pack[1], 0, 0};
|
||||
if(!ntagCardPageWrite(maxPage + PAGE_PACK_OFFSET, packPageData, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//uint8_t pageData[18];
|
||||
//uint8_t dataSize = sizeof(pageData);
|
||||
//if(!ntagCard4PagesRead(maxPage + PAGE_CFG1_OFFSET, pageData, &dataSize)) {
|
||||
// return false;
|
||||
//}
|
||||
uint8_t accessByteData = readAndWrite ? 0x80 : 0x00;
|
||||
accessByteData |= negAuthAttemptsLim & 0x07;
|
||||
uint8_t cfg1PageData[4] = {accessByteData, 0, 0, 0};
|
||||
if(!ntagCardPageWrite(maxPage + PAGE_CFG1_OFFSET, cfg1PageData, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set start page to enable the password verification at the end of the procedure
|
||||
uint8_t cfg0PageData[4] = {0, 0, 0, startPage};
|
||||
if(!ntagCardPageWrite(maxPage + PAGE_CFG0_OFFSET, cfg0PageData, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rfid::ntagDisableAuthentication() {
|
||||
DEBUG_PRINTLN("ntagDisableAuthentication");
|
||||
uint8_t maxPage = getCardMaxPage();
|
||||
|
||||
uint8_t defaultPassword[4] = {0xff, 0xff, 0xff, 0xff};
|
||||
// Reset password
|
||||
if(!ntagCardPageWrite(maxPage + PAGE_PWD_OFFSET, defaultPassword, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t cfg0PageData[4] = {0, 0, 0, 0xff};
|
||||
if(!ntagCardPageWrite(maxPage + PAGE_CFG0_OFFSET, cfg0PageData, 4)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rfid::ntagAuth(NtagAuthPassword *password) {
|
||||
if(!password) {
|
||||
DEBUG_PRINTLN(F("ntagAuth password is null"));
|
||||
return false;
|
||||
}
|
||||
if (!isCardDetected()) {
|
||||
DEBUG_PRINTLN(F("ntagAuth card is not detected"));
|
||||
return false;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
DEBUG_PRINTLN(F("Authenticating..."));
|
||||
DEBUG_PRINT(F("Password: "));
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
DEBUG_PRINT_FORMAT(password->pass[i], HEX);
|
||||
DEBUG_PRINT(F(" "));
|
||||
}
|
||||
DEBUG_PRINTLN("");
|
||||
DEBUG_PRINT(F("Pack: "));
|
||||
for(uint8_t i = 0; i < 2; i++) {
|
||||
DEBUG_PRINT_FORMAT(password->pack[i], HEX);
|
||||
DEBUG_PRINT(F(" "));
|
||||
}
|
||||
DEBUG_PRINTLN("");
|
||||
#endif
|
||||
uint8_t packReturn[2] = {0, 0};
|
||||
auto status = (MFRC522::StatusCode)mfrc522.PCD_NTAG21x_Auth(&password->pass[0], packReturn);
|
||||
DEBUG_PRINT(F("Pack from card: 0x"));
|
||||
DEBUG_PRINT_FORMAT(packReturn[0], HEX);
|
||||
DEBUG_PRINT(F(" 0x"));
|
||||
DEBUG_PRINTLN_FORMAT(packReturn[1], HEX);
|
||||
|
||||
if(status != MFRC522::STATUS_OK) {
|
||||
DEBUG_PRINT(F("Auth failed, status: 0x"));
|
||||
DEBUG_PRINTLN_FORMAT(status, HEX);
|
||||
if (status == MFRC522::STATUS_TIMEOUT) {
|
||||
byte atqa_answer[2];
|
||||
byte atqa_size = 2;
|
||||
mfrc522.PICC_WakeupA(atqa_answer, &atqa_size);
|
||||
|
||||
if (!mfrc522.PICC_ReadCardSerial()) {
|
||||
DEBUG_PRINTLN(F("ReadCardSerial failed"));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rfid::ntagTryAuth(bool ignoreAuthError) {
|
||||
if(authPwd.pass[0] != 0xFF || authPwd.pass[1] != 0xFF || authPwd.pass[2] != 0xFF || authPwd.pass[3] != 0xFF) {
|
||||
if(!ntagAuth(&authPwd)) {
|
||||
if(!ignoreAuthError) {
|
||||
return false;
|
||||
}
|
||||
DEBUG_PRINTLN(F("ignore auth error"));
|
||||
}
|
||||
}
|
||||
authenticated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rfid::ntagCard4PagesRead(uint8_t pageAdr, byte *data, byte *size, bool ignoreAuthError) {
|
||||
if(*size < 18) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pageAdr >= CARD_PAGE_INIT && !authenticated) {
|
||||
if (!ntagTryAuth(ignoreAuthError)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(pageAdr, data, size);
|
||||
|
||||
if(status != MFRC522::STATUS_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rfid::ntagCardPageWrite(uint8_t pageAdr, byte *data, byte size, bool ignoreAuthError) {
|
||||
DEBUG_PRINT(F("ntagCardPageWrite pageAdr: "));
|
||||
DEBUG_PRINT(pageAdr);
|
||||
DEBUG_PRINT(F(" size: "));
|
||||
DEBUG_PRINTLN(size);
|
||||
if(pageAdr < 2 || size < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!authenticated || !ignoreAuthError) {
|
||||
if(!ntagTryAuth(ignoreAuthError)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto status = (MFRC522::StatusCode)mfrc522.MIFARE_Ultralight_Write(pageAdr, data, size);
|
||||
|
||||
if(status != MFRC522::STATUS_OK) {
|
||||
DEBUG_PRINT(F("ntagCardPageWrite failed, status: 0x"));
|
||||
DEBUG_PRINTLN_FORMAT(status, HEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t Rfid::getCardMaxPage() {
|
||||
switch(cardType) {
|
||||
case CardType::MIFARE_MINI:
|
||||
return 17;
|
||||
case CardType::MIFARE_1K:
|
||||
return 50;
|
||||
case CardType::MIFARE_4K:
|
||||
return 98;
|
||||
case CardType::MIFARE_UL:
|
||||
return 39;
|
||||
case CardType::NTAG216:
|
||||
return 225;
|
||||
case CardType::NTAG215:
|
||||
return 129;
|
||||
case CardType::NTAG213:
|
||||
return 39;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CardType Rfid::getCardType() {
|
||||
return cardType;
|
||||
}
|
||||
|
||||
bool Rfid::cardPageRead(uint8_t pageAdr, byte *data, uint8_t size, bool ignoreAuthError) {
|
||||
uint8_t maxPage = getCardMaxPage();
|
||||
|
||||
if(pageAdr > maxPage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
byte pageData[18];
|
||||
byte dataSize = sizeof(pageData);
|
||||
switch(cardType) {
|
||||
case CardType::MIFARE_MINI:
|
||||
case CardType::MIFARE_1K:
|
||||
case CardType::MIFARE_4K:
|
||||
result = mifareCardPageRead(pageAdr, pageData, &dataSize);
|
||||
break;
|
||||
case CardType::MIFARE_UL:
|
||||
case CardType::NTAG213:
|
||||
case CardType::NTAG215:
|
||||
case CardType::NTAG216:
|
||||
default:
|
||||
result = ntagCard4PagesRead(pageAdr, pageData, &dataSize, ignoreAuthError);
|
||||
break;
|
||||
}
|
||||
|
||||
if(result) {
|
||||
memcpy(data, pageData, size);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Rfid::cardPageWrite(uint8_t pageAdr, const byte *data, uint8_t size, bool ignoreAuthError) {
|
||||
uint8_t maxPage = getCardMaxPage();
|
||||
|
||||
if(pageAdr > maxPage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte pageData[16];
|
||||
memset(pageData, 0, sizeof(pageData));
|
||||
memcpy(pageData, data, size);
|
||||
|
||||
switch(cardType) {
|
||||
case CardType::MIFARE_MINI:
|
||||
case CardType::MIFARE_1K:
|
||||
case CardType::MIFARE_4K:
|
||||
return mifareCardPageWrite(pageAdr, pageData, sizeof(pageData));
|
||||
case CardType::MIFARE_UL:
|
||||
case CardType::NTAG213:
|
||||
case CardType::NTAG215:
|
||||
case CardType::NTAG216:
|
||||
default:
|
||||
return ntagCardPageWrite(pageAdr, pageData, sizeof(pageData), ignoreAuthError);
|
||||
}
|
||||
}
|
||||
|
||||
bool Rfid::cardPageWrite(uint8_t pageAdr, uint32_t value) {
|
||||
byte data[4];
|
||||
data[0] = (value >> 24) & 0xFF;
|
||||
data[1] = (value >> 16) & 0xFF;
|
||||
data[2] = (value >> 8) & 0xFF;
|
||||
data[3] = value & 0xFF;
|
||||
return cardPageWrite(pageAdr, data, 4);
|
||||
}
|
||||
|
||||
bool Rfid::cardWrite(uint8_t startPageAdr, const byte *data, uint16_t size) {
|
||||
uint8_t pageAddr = startPageAdr;
|
||||
for(uint8_t i = 0; i < size/4; ++i) {
|
||||
if(!cardPageWrite(pageAddr++, data + i*4)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t tailSize = size%4;
|
||||
if(tailSize > 0) {
|
||||
if(!cardPageWrite(pageAddr, data + size - tailSize, tailSize)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rfid::cardErase(uint8_t beginPageAddr, uint8_t endPageAddr) {
|
||||
for(uint8_t pageAddr = endPageAddr; pageAddr >= beginPageAddr; --pageAddr) {
|
||||
if(!cardPageErase(pageAddr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rfid::cardPageErase(uint8_t pageAddr) {
|
||||
DEBUG_PRINT(F("Erasing page "));
|
||||
DEBUG_PRINTLN(pageAddr);
|
||||
byte pageData[4];
|
||||
if(!cardPageRead(pageAddr, pageData)) {
|
||||
return false;
|
||||
}
|
||||
for(uint8_t i = 0; i < 4; ++i) {
|
||||
if(pageData[i] != 0) {
|
||||
const byte emptyBlock[] = {0,0,0,0};
|
||||
return cardPageWrite(pageAddr, emptyBlock);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Rfid::cardErase4Pages(uint8_t pageAddr) {
|
||||
if (!isCardDetected()) {
|
||||
return false;
|
||||
}
|
||||
switch(cardType) {
|
||||
case CardType::MIFARE_MINI:
|
||||
case CardType::MIFARE_1K:
|
||||
case CardType::MIFARE_4K: {
|
||||
for(uint8_t i = 0; i < 4; ++i) {
|
||||
if(!cardPageErase(pageAddr + 3 - i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case CardType::NTAG213:
|
||||
case CardType::NTAG215:
|
||||
case CardType::NTAG216: {
|
||||
DEBUG_PRINT(F("Checking pages at "));
|
||||
DEBUG_PRINTLN(pageAddr);
|
||||
byte pageData[18];
|
||||
byte dataSize = sizeof(pageData);
|
||||
if(!ntagCard4PagesRead(pageAddr, pageData, &dataSize)) {
|
||||
return false;
|
||||
}
|
||||
for(uint8_t i = 0; i < 4; ++i) {
|
||||
for(uint8_t j = 0; j < 4; ++j) {
|
||||
uint8_t offset = (3 - i);
|
||||
if(pageData[offset*4 + j] != 0) {
|
||||
const byte emptyBlock[] = {0,0,0,0};
|
||||
if(!ntagCardPageWrite(pageAddr + offset, emptyBlock, sizeof(emptyBlock))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Rfid::cardEnableDisableAuthentication(bool writeProtection, bool readProtection) {
|
||||
if (!isCardDetected()) {
|
||||
return false;
|
||||
}
|
||||
switch(cardType) {
|
||||
case CardType::MIFARE_MINI:
|
||||
case CardType::MIFARE_1K:
|
||||
case CardType::MIFARE_4K: {
|
||||
// TODO: not implemented yet
|
||||
return true;
|
||||
}
|
||||
case CardType::NTAG213:
|
||||
case CardType::NTAG215:
|
||||
case CardType::NTAG216: {
|
||||
if(!writeProtection) {
|
||||
return ntagDisableAuthentication();
|
||||
}
|
||||
// Enable authentication from page 4 and with unlimited negative password verification attempts
|
||||
return ntagSetPassword(&authPwd, readProtection, 0, CARD_PAGE_INIT);
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#ifndef SPORTIDUINO_RFID_H
|
||||
#define SPORTIDUINO_RFID_H
|
||||
|
||||
#include <MFRC522.h>
|
||||
|
||||
#define MIN_ANTENNA_GAIN 2
|
||||
#define MAX_ANTENNA_GAIN 7
|
||||
|
||||
#define DEFAULT_ANTENNA_GAIN 4
|
||||
|
||||
#define CARD_PAGE_INIT 4
|
||||
#define CARD_PAGE_INIT_TIME 5
|
||||
#define CARD_PAGE_LAST_RECORD_INFO 6
|
||||
#define CARD_PAGE_INFO1 6
|
||||
#define CARD_PAGE_INFO2 7
|
||||
#define CARD_PAGE_START 8
|
||||
|
||||
#define CARD_PAGE_PASS 5
|
||||
#define CARD_PAGE_DATE 6
|
||||
#define CARD_PAGE_TIME 7
|
||||
#define CARD_PAGE_STATION_NUM 6
|
||||
#define CARD_PAGE_BACKUP_START 6
|
||||
|
||||
#define PAGE_CFG0_OFFSET 2
|
||||
#define PAGE_CFG1_OFFSET 3
|
||||
#define PAGE_PWD_OFFSET 4
|
||||
#define PAGE_PACK_OFFSET 5
|
||||
|
||||
enum class CardType : byte {
|
||||
UNKNOWN = 0,
|
||||
ISO_14443_4 = 1,
|
||||
ISO_18092 = 2,
|
||||
MIFARE_MINI = 3,
|
||||
MIFARE_1K = 4,
|
||||
MIFARE_4K = 5,
|
||||
MIFARE_UL = 6,
|
||||
MIFARE_PLUS = 7,
|
||||
TNP3XXX = 8,
|
||||
NTAG213 = 9,
|
||||
NTAG215 = 10,
|
||||
NTAG216 = 11
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
byte pass[4];
|
||||
byte pack[2];
|
||||
} NtagAuthPassword;
|
||||
|
||||
class Rfid {
|
||||
public:
|
||||
void init(uint8_t ssPin, uint8_t rstPin, uint8_t newAntennaGain = DEFAULT_ANTENNA_GAIN);
|
||||
|
||||
void clearLastCardUid();
|
||||
|
||||
void setAntennaGain(uint8_t newAntennaGain);
|
||||
void setAuthPassword(uint8_t *password);
|
||||
|
||||
/**
|
||||
* Begins to work with RFID module
|
||||
* Turn on RC522, detect a card and return the card type if a new one has presented else return 0 if the same card has presented or 0xFF if no any card
|
||||
*/
|
||||
void begin(uint8_t newAntennaGain = 0);
|
||||
|
||||
/**
|
||||
* Stops to work with RFID module
|
||||
*/
|
||||
void end();
|
||||
|
||||
/**
|
||||
* Returns true if any card has been detected by RFID module
|
||||
*/
|
||||
bool isCardDetected();
|
||||
|
||||
bool isNewCardDetected();
|
||||
|
||||
bool cardWrite(uint8_t startPageAdr, const byte *data, uint16_t size);
|
||||
|
||||
bool cardErase(uint8_t beginPageAddr, uint8_t endPageAddr);
|
||||
|
||||
bool cardPageErase(uint8_t pageAddr);
|
||||
|
||||
bool cardErase4Pages(uint8_t pageAddr);
|
||||
|
||||
/**
|
||||
* Reads data from a card page. Buffer size should be 4 bytes!
|
||||
*/
|
||||
bool cardPageRead(uint8_t pageAdr, byte *data, uint8_t size = 4, bool ignoreAuthError = true);
|
||||
|
||||
/**
|
||||
* Writes data to a card page. Buffer size should be 4 bytes!
|
||||
*/
|
||||
bool cardPageWrite(uint8_t pageAdr, const byte *data, uint8_t size = 4, bool ignoreAuthError = true);
|
||||
|
||||
bool cardPageWrite(uint8_t pageAdr, uint32_t value);
|
||||
|
||||
/**
|
||||
* Returns max page address of the presented card
|
||||
*/
|
||||
uint8_t getCardMaxPage();
|
||||
|
||||
/**
|
||||
* Returns type of the card
|
||||
*/
|
||||
CardType getCardType();
|
||||
|
||||
bool cardEnableDisableAuthentication(bool writeProtection, bool readProtection = false);
|
||||
|
||||
private:
|
||||
// data buffer size should be greater 18 bytes
|
||||
bool mifareCardPageRead(uint8_t pageAdr, byte *data, byte *size);
|
||||
// data buffer size should be greater 16 bytes
|
||||
bool mifareCardPageWrite(uint8_t pageAdr, byte *data, byte size);
|
||||
// data buffer size should be greater 18 bytes
|
||||
bool ntagCard4PagesRead(uint8_t pageAdr, byte *data, byte *size, bool ignoreAuthError = true);
|
||||
bool ntagTryAuth(bool ignoreAuthError);
|
||||
bool ntagAuth(NtagAuthPassword *password);
|
||||
bool ntagSetPassword(NtagAuthPassword *password, bool readAndWrite, uint8_t negAuthAttemptsLim, uint8_t startPage);
|
||||
bool ntagDisableAuthentication();
|
||||
// data buffer size should be greater 4 bytes
|
||||
bool ntagCardPageWrite(uint8_t pageAdr, byte *data, byte size, bool ignoreAuthError = true);
|
||||
|
||||
MFRC522 mfrc522;
|
||||
NtagAuthPassword authPwd;
|
||||
MFRC522::Uid lastCardUid;
|
||||
uint8_t rfidSsPin = 0;
|
||||
uint8_t rfidRstPin = 0;
|
||||
uint8_t antennaGain = 0;
|
||||
CardType cardType = CardType::UNKNOWN;
|
||||
bool authenticated = false;
|
||||
};
|
||||
|
||||
#endif // SPORTIDUINO_RFID_H
|
||||
|
||||
+259
@@ -0,0 +1,259 @@
|
||||
#include <EEPROM.h>
|
||||
#include <Adafruit_SleepyDog.h>
|
||||
#include <string.h>
|
||||
#include "sportiduino.h"
|
||||
|
||||
#define SERIAL_DATA_MAX_SIZE 28
|
||||
#define SERIAL_TIMEOUT 10
|
||||
|
||||
void majEepromWrite(uint16_t adr, uint8_t val) {
|
||||
uint8_t oldVal = majEepromRead(adr);
|
||||
if(val != oldVal) {
|
||||
for(uint16_t i = 0; i < 3; i++) {
|
||||
EEPROM.write(adr + i, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t majEepromRead(uint16_t adr) {
|
||||
uint8_t val1 = EEPROM.read(adr);
|
||||
uint8_t val2 = EEPROM.read(adr + 1);
|
||||
uint8_t val3 = EEPROM.read(adr + 2);
|
||||
|
||||
if(val1 == val2 || val1 == val3) {
|
||||
return val1;
|
||||
} else if(val2 == val3) {
|
||||
return val2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void beep_w(const uint8_t ledPin, const uint8_t buzPin, uint16_t freq, uint16_t ms, uint8_t n, uint16_t pause) {
|
||||
if (pause == 0) {
|
||||
pause = (ms > 200) ? 200 : ms;
|
||||
}
|
||||
for(uint8_t i = 0; i < n; i++) {
|
||||
Watchdog.reset();
|
||||
|
||||
digitalWrite(ledPin, HIGH);
|
||||
#if !defined(SILENT_BEEP)
|
||||
if(freq > 0) {
|
||||
tone(buzPin, freq, ms);
|
||||
} else {
|
||||
digitalWrite(buzPin, HIGH);
|
||||
}
|
||||
#endif
|
||||
|
||||
delay(ms);
|
||||
Watchdog.reset();
|
||||
|
||||
digitalWrite(ledPin, LOW);
|
||||
digitalWrite(buzPin, LOW);
|
||||
|
||||
if(i < n - 1) {
|
||||
delay(pause);
|
||||
Watchdog.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool findNewPage(Rfid *rfid, uint8_t *newPage, uint8_t *lastNum) {
|
||||
DEBUG_PRINTLN(F("findNewPage"));
|
||||
uint8_t startPage = CARD_PAGE_START;
|
||||
uint8_t endPage = rfid->getCardMaxPage() + 1; // page after last page
|
||||
uint8_t page = startPage;
|
||||
byte pageData[4] = {0,0,0,0};
|
||||
byte num = 0;
|
||||
|
||||
*newPage = 0;
|
||||
*lastNum = 0;
|
||||
|
||||
while(startPage < endPage) {
|
||||
page = (startPage + endPage)/2;
|
||||
DEBUG_PRINT(F("page: "));
|
||||
DEBUG_PRINTLN(page);
|
||||
|
||||
if(!rfid->cardPageRead(page, pageData)) {
|
||||
DEBUG_PRINTLN(F("page read failed"));
|
||||
return false;
|
||||
}
|
||||
|
||||
num = pageData[0];
|
||||
|
||||
if(num == 0) {
|
||||
endPage = page;
|
||||
} else {
|
||||
startPage = (startPage != page)? page : page + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(num > 0) {
|
||||
++page;
|
||||
}
|
||||
DEBUG_PRINT(F("new page: "));
|
||||
DEBUG_PRINT(page);
|
||||
DEBUG_PRINT(F(", num: "));
|
||||
DEBUG_PRINTLN(num);
|
||||
|
||||
*newPage = page;
|
||||
*lastNum = num;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pageIsEmpty(const byte *pageData) {
|
||||
return (pageData[0] == 0 && pageData[1] == 0 && pageData[2] == 0 && pageData[3] == 0);
|
||||
}
|
||||
|
||||
bool uint32ToByteArray(uint32_t value, byte *byteArray) {
|
||||
for(uint8_t i = 0; i < 4; ++i) {
|
||||
byteArray[3 - i] = value & 0xff;
|
||||
value >>= 8;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t byteArrayToUint32(const byte *byteArray) {
|
||||
uint32_t value = 0;
|
||||
for(uint8_t i = 0; i < 4; ++i) {
|
||||
value <<= 8;
|
||||
value |= byteArray[i];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool readConfig(uint8_t *config, uint8_t configSize, uint16_t eepromConfigAddress) {
|
||||
uint16_t eepromAdr = eepromConfigAddress;
|
||||
for(uint8_t i = 0; i < configSize; ++i) {
|
||||
*((uint8_t*)config + i) = majEepromRead(eepromAdr);
|
||||
eepromAdr += 3;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool writeConfig(uint8_t *newConfig, uint8_t configSize, uint16_t eepromConfigAddress) {
|
||||
uint16_t eepromAdr = eepromConfigAddress;
|
||||
for(uint8_t i = 0; i < configSize; ++i) {
|
||||
majEepromWrite(eepromAdr, *((uint8_t*)newConfig + i));
|
||||
eepromAdr += 3;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SerialProtocol::init(uint8_t _startByte, uint32_t _baudrate) {
|
||||
startByte = _startByte;
|
||||
baudrate = _baudrate;
|
||||
Serial.setTimeout(SERIAL_TIMEOUT);
|
||||
begin();
|
||||
}
|
||||
|
||||
void SerialProtocol::begin() {
|
||||
Serial.begin(baudrate);
|
||||
}
|
||||
|
||||
void SerialProtocol::end() {
|
||||
Serial.end();
|
||||
}
|
||||
|
||||
void SerialProtocol::start(uint8_t code) {
|
||||
serialDataPos = 3;
|
||||
serialPacketCount = 0;
|
||||
memset(serialBuffer, 0, SERIAL_PACKET_SIZE);
|
||||
|
||||
serialBuffer[0] = startByte;
|
||||
serialBuffer[1] = code;
|
||||
}
|
||||
|
||||
void SerialProtocol::send() {
|
||||
uint8_t dataSize = serialDataPos - 3; // minus start, resp code, datalen
|
||||
|
||||
if(dataSize > SERIAL_DATA_MAX_SIZE) {
|
||||
dataSize = serialPacketCount + 0x1E;
|
||||
serialDataPos = SERIAL_PACKET_SIZE - 1;
|
||||
serialPacketCount++;
|
||||
}
|
||||
|
||||
serialBuffer[2] = dataSize;
|
||||
serialBuffer[serialDataPos] = checkSum(serialBuffer, dataSize);
|
||||
|
||||
for(uint8_t i = 0; i <= serialDataPos; i++) {
|
||||
Serial.write(serialBuffer[i]);
|
||||
}
|
||||
|
||||
serialDataPos = 3;
|
||||
}
|
||||
|
||||
void SerialProtocol::add(uint8_t dataByte) {
|
||||
if(serialDataPos >= SERIAL_PACKET_SIZE - 1) {
|
||||
serialDataPos++; // to indicate that we going to send packet count
|
||||
send();
|
||||
}
|
||||
|
||||
serialBuffer[serialDataPos] = dataByte;
|
||||
serialDataPos++;
|
||||
}
|
||||
|
||||
void SerialProtocol::addUint32(uint32_t data) {
|
||||
uint8_t b[4];
|
||||
uint32ToByteArray(data, b);
|
||||
add(b, 4);
|
||||
}
|
||||
|
||||
void SerialProtocol::add(const uint8_t *data, uint8_t size) {
|
||||
for(uint8_t i = 0; i < size; ++i) {
|
||||
add(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t SerialProtocol::checkSum(uint8_t *buffer, uint8_t dataSize) {
|
||||
// if at dataSize position we have packet count
|
||||
if(dataSize > SERIAL_DATA_MAX_SIZE) {
|
||||
dataSize = SERIAL_DATA_MAX_SIZE;
|
||||
}
|
||||
|
||||
uint8_t len = dataSize + 2; // + cmd/resp byte + length byte
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 1; i <= len; ++i) {
|
||||
sum += buffer[i];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint8_t *SerialProtocol::read(bool *error, uint8_t *code, uint8_t *dataSize) {
|
||||
*error = false;
|
||||
memset(serialBuffer, 0, SERIAL_PACKET_SIZE);
|
||||
if(Serial.available() > 0) {
|
||||
uint8_t b = Serial.peek();
|
||||
if(b == startByte) {
|
||||
Serial.readBytes(serialBuffer, SERIAL_PACKET_SIZE);
|
||||
|
||||
*dataSize = serialBuffer[2];
|
||||
|
||||
// if at dataSize position we have packet count
|
||||
if(*dataSize > SERIAL_DATA_MAX_SIZE) {
|
||||
*dataSize = SERIAL_DATA_MAX_SIZE;
|
||||
}
|
||||
|
||||
if(serialBuffer[*dataSize + 3] != checkSum(serialBuffer, *dataSize)) {
|
||||
*error = true;
|
||||
return nullptr;
|
||||
}
|
||||
*code = serialBuffer[1];
|
||||
return &serialBuffer[3];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SerialProtocol::dropByte() {
|
||||
if(Serial.available() > 0) {
|
||||
// Drop byte
|
||||
Serial.read();
|
||||
}
|
||||
}
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
#ifndef SPORTIDUINO_H
|
||||
#define SPORTIDUINO_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "debug.h"
|
||||
#include "rfid.h"
|
||||
|
||||
enum StationNum {
|
||||
START_STATION_NUM = 240,
|
||||
FINISH_STATION_NUM = 245,
|
||||
CHECK_STATION_NUM = 248,
|
||||
CLEAR_STATION_NUM = 249
|
||||
};
|
||||
|
||||
enum MasterCard {
|
||||
MASTER_CARD_AUTH_PASSWORD = 248,
|
||||
MASTER_CARD_STATE = 249,
|
||||
MASTER_CARD_SET_TIME = 250,
|
||||
MASTER_CARD_SET_NUMBER = 251,
|
||||
MASTER_CARD_SLEEP = 252,
|
||||
MASTER_CARD_READ_BACKUP = 253,
|
||||
MASTER_CARD_CONFIG = 254,
|
||||
MASTER_CARD_PASSWORD = 255
|
||||
};
|
||||
|
||||
#define MASTER_CARD_SIGN 0xff
|
||||
#define FAST_PUNCH_SIGN 0xaa // page6[3]
|
||||
|
||||
#define SERIAL_PACKET_SIZE 32
|
||||
|
||||
#define MAX_FW_MINOR_VERS 239
|
||||
|
||||
/**
|
||||
* Writes data with a majority backup in three cells of EEPROM
|
||||
*/
|
||||
void majEepromWrite (uint16_t adr, uint8_t val);
|
||||
|
||||
/**
|
||||
* Reads data with a majority backup from EEPROM
|
||||
*/
|
||||
uint8_t majEepromRead(uint16_t adr);
|
||||
|
||||
/**
|
||||
* Turn on led and buzzer for given ms n times
|
||||
* @param freq the frequency of your buzzer if you have solded the buzzer without a generator else 0
|
||||
*/
|
||||
void beep_w(const uint8_t ledPin, const uint8_t buzPin, uint16_t freq, uint16_t ms, uint8_t n, uint16_t pause = 0);
|
||||
|
||||
bool findNewPage(Rfid *rfid, uint8_t *newPage, uint8_t *lastNum);
|
||||
bool pageIsEmpty(const byte *pageData);
|
||||
|
||||
bool uint32ToByteArray(uint32_t value, byte *byteArray);
|
||||
uint32_t byteArrayToUint32(const byte *byteArray);
|
||||
bool pageIsEmpty(const byte *pageData);
|
||||
|
||||
bool readConfig(uint8_t *config, uint8_t configSize, uint16_t eepromConfigAddress);
|
||||
bool writeConfig(uint8_t *newConfig, uint8_t configSize, uint16_t eepromConfigAddress);
|
||||
|
||||
|
||||
class SerialProtocol {
|
||||
public:
|
||||
void init(uint8_t _startByte, uint32_t baudrate = 9600);
|
||||
void begin();
|
||||
void end();
|
||||
void start(uint8_t code);
|
||||
void add(uint8_t dataByte);
|
||||
void addUint32(uint32_t data);
|
||||
void add(const uint8_t *data, uint8_t size);
|
||||
void send();
|
||||
uint8_t *read(bool *error, uint8_t *code, uint8_t *dataSize);
|
||||
void dropByte();
|
||||
|
||||
private:
|
||||
uint8_t checkSum(uint8_t *buffer, uint8_t dataSize);
|
||||
|
||||
uint8_t startByte = 0;
|
||||
uint8_t serialBuffer[SERIAL_PACKET_SIZE];
|
||||
uint8_t serialDataPos = 3;
|
||||
uint8_t serialPacketCount = 0;
|
||||
uint32_t baudrate = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user