Files
MarklinController/mfrc522.h
2022-03-10 22:25:35 +01:00

236 lines
10 KiB
C++

#pragma once
#include "shiftreg.h"
#include "softspim.h"
#include "defines.h"
#include "serial.h"
class Mfrc522
{
public:
// Error codes.
static constexpr uint8_t OK = 0; // Everything A-OK.
static constexpr uint8_t NOTAGERR = 1; // No tag error
static constexpr uint8_t TIMEOUT = 2; // Timeout error
static constexpr uint8_t LEN = 3; // Buffer length error
static constexpr uint8_t COLLISION = 4; // Chip collision
static constexpr uint8_t CRC = 5; // CRC incorrect collision
static constexpr uint8_t BUSY = 6; // System is busy
static constexpr uint8_t ERR = 7; // General error
// Command words
static constexpr uint8_t IDLE = 0x00; // NO action; Cancel the current command
static constexpr uint8_t MEM = 0x01; // Store 25 byte into the internal buffer.
static constexpr uint8_t GENID = 0x02; // Generates a 10 byte random ID number.
static constexpr uint8_t CALCCRC = 0x03; // CRC Calculate or selftest.
static constexpr uint8_t TRANSMIT = 0x04; // Transmit data
static constexpr uint8_t NOCMDCH = 0x07; // No command change.
static constexpr uint8_t RECEIVE = 0x08; // Receive Data
static constexpr uint8_t TRANSCEIVE = 0x0C; // Transmit and receive data
static constexpr uint8_t AUTHENT = 0x0E; // Authentication Key
static constexpr uint8_t SOFTRESET = 0x0F; // Reset
// Tag command words
static constexpr uint8_t MF1_REQIDL = 0x26; // find the antenna area does not enter hibernation
static constexpr uint8_t MF1_REQALL = 0x52; // find all the tags antenna area
static constexpr uint8_t MF1_ANTICOLL = 0x93; // anti-collision
static constexpr uint8_t MF1_SELECTTAG = 0x93; // ??? election tag
static constexpr uint8_t MF1_AUTHENT1A = 0x60; // authentication key A
static constexpr uint8_t MF1_AUTHENT1B = 0x61; // authentication key B
static constexpr uint8_t MF1_READ = 0x30; // Read Block
static constexpr uint8_t MF1_WRITE = 0xA0; // write block
static constexpr uint8_t MF1_DECREMENT = 0xC0; // debit
static constexpr uint8_t MF1_INCREMENT = 0xC1; // recharge
static constexpr uint8_t MF1_RESTORE = 0xC2; // transfer block data to the buffer
static constexpr uint8_t MF1_TRANSFER = 0xB0; // save the data in the buffer
static constexpr uint8_t MF1_HALT = 0x50; // Sleep
//Page 0:Command and Status
static constexpr uint8_t CommandReg = 0x01;
static constexpr uint8_t ComIEnReg = 0x02;
static constexpr uint8_t DivIEnReg = 0x03;
static constexpr uint8_t ComIrqReg = 0x04;
static constexpr uint8_t DivIrqReg = 0x05;
static constexpr uint8_t ErrorReg = 0x06;
static constexpr uint8_t Status1Reg = 0x07;
static constexpr uint8_t Status2Reg = 0x08;
static constexpr uint8_t FIFODataReg = 0x09;
static constexpr uint8_t FIFOLevelReg = 0x0A;
static constexpr uint8_t WaterLevelReg = 0x0B;
static constexpr uint8_t ControlReg = 0x0C;
static constexpr uint8_t BitFramingReg = 0x0D;
static constexpr uint8_t CollReg = 0x0E;
//Page 1:Command
static constexpr uint8_t ModeReg = 0x11;
static constexpr uint8_t TxModeReg = 0x12;
static constexpr uint8_t RxModeReg = 0x13;
static constexpr uint8_t TxControlReg = 0x14;
static constexpr uint8_t TxAutoReg = 0x15;
static constexpr uint8_t TxSelReg = 0x16;
static constexpr uint8_t RxSelReg = 0x17;
static constexpr uint8_t RxThresholdReg= 0x18;
static constexpr uint8_t DemodReg = 0x19;
static constexpr uint8_t MifareReg = 0x1C;
static constexpr uint8_t SerialSpeedReg= 0x1F;
//Page 2:CFG
static constexpr uint8_t CRCResultRegH = 0x21;
static constexpr uint8_t CRCResultRegL = 0x22;
static constexpr uint8_t Reserved21 = 0x23;
static constexpr uint8_t ModWidthReg = 0x24;
static constexpr uint8_t RFCfgReg = 0x26;
static constexpr uint8_t GsNReg = 0x27;
static constexpr uint8_t CWGsPReg = 0x28;
static constexpr uint8_t ModGsPReg = 0x29;
static constexpr uint8_t TModeReg = 0x2A;
static constexpr uint8_t TPrescalerReg = 0x2B;
static constexpr uint8_t TReloadRegH = 0x2C;
static constexpr uint8_t TReloadRegL = 0x2D;
static constexpr uint8_t TCounterValueRegH = 0x2E;
static constexpr uint8_t TCounterValueRegL = 0x2F;
//Page 3:TestRegister
static constexpr uint8_t TestSel1Reg = 0x31;
static constexpr uint8_t TestSel2Reg = 0x32;
static constexpr uint8_t TestPinEnReg = 0x33;
static constexpr uint8_t TestPinValueReg = 0x34;
static constexpr uint8_t TestBusReg = 0x35;
static constexpr uint8_t AutoTestReg = 0x36;
static constexpr uint8_t VersionReg = 0x37;
static constexpr uint8_t AnalogTestReg = 0x38;
static constexpr uint8_t TestDAC1Reg = 0x39;
static constexpr uint8_t TestDAC2Reg = 0x3A;
static constexpr uint8_t TestADCReg = 0x3B;
// PICC (tag) commands
// The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4)
// REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
static constexpr uint8_t PICC_CMD_REQA = 0x26;
// Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.
static constexpr uint8_t PICC_CMD_WUPA = 0x52; // Cascade Tag. Not really a command, but used during anti collision.
static constexpr uint8_t PICC_CMD_CT = 0x88;
static constexpr uint8_t PICC_CMD_SEL_CL1 = 0x93; // Anti collision/Select, Cascade Level 1
static constexpr uint8_t PICC_CMD_SEL_CL2 = 0x95; // Anti collision/Select, Cascade Level 1
static constexpr uint8_t PICC_CMD_SEL_CL3 = 0x97; // Anti collision/Select, Cascade Level 1
// HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT.
// The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9)
// Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector.
// The read/write commands can also be used for MIFARE Ultralight.
static constexpr uint8_t PICC_CMD_HLTA = 0x50;
static constexpr uint8_t PICC_CMD_MF_AUTH_KEY_A = 0x60; // Perform authentication with Key A
static constexpr uint8_t PICC_CMD_MF_AUTH_KEY_B = 0x61; // Perform authentication with Key B
// Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight.
static constexpr uint8_t PICC_CMD_MF_READ = 0x30;
// Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight.
static constexpr uint8_t PICC_CMD_MF_WRITE = 0xA0;
// Decrements the contents of a block and stores the result in the internal data register.
static constexpr uint8_t PICC_CMD_MF_DECREMENT = 0xC0;
// Increments the contents of a block and stores the result in the internal data register.
static constexpr uint8_t PICC_CMD_MF_INCREMENT = 0xC1;
// Reads the contents of a block into the internal data register.
static constexpr uint8_t PICC_CMD_MF_RESTORE = 0xC2;
// Writes the contents of the internal data register to a block.
static constexpr uint8_t PICC_CMD_MF_TRANSFER = 0xB0;
// The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
// The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight.
static constexpr uint8_t PICC_CMD_UL_WRITE = 0xA2; // Writes one 4 byte page to the PICC
class Uid
{
public:
uint8_t size; // Number of bytes in the UID. 4, 7 or 10.
uint8_t uidByte[10];
uint8_t sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection.
bool operator==(Uid& in)
{
if(size != in.size)
return false;
for(uint8_t i = 0; i < size; ++i)
{
if(uidByte[i] != in.uidByte[i])
return false;
}
return true;
}
bool operator!=(Uid& in)
{
return !operator==(in);
}
};
// Modes
static constexpr uint8_t MODE_IDLE = 0;
static constexpr uint8_t MODE_TRANSCEIVE = 1;
private:
ShiftReg<NFC_PORTS>* _csReg;
SpiMaster* _spi;
uint8_t _csPin;
void (*_tagEnterdCb)(Mfrc522*, void*);
void* _userData;
void (*_transceiveCb)(uint8_t ret, Mfrc522* reader, uint8_t* response, uint8_t responseLen, void* userData);
void* _transceiveUserData;
static constexpr uint8_t reponseBufferLen = 16;
static uint8_t reponseBuffer[reponseBufferLen];
volatile uint8_t mode = MODE_IDLE;
volatile bool irqDetect = false;
void setupTransceive(uint8_t *sendData, uint8_t sendLen, uint8_t validBits = 0, uint8_t rxAlign = 0);
uint8_t transceiveAsync(void (*transceiveCb)(uint8_t, Mfrc522*, uint8_t*, uint8_t, void*), void* userData, uint8_t *sendData,
uint8_t sendLen, uint8_t validBits = 0, uint8_t rxAlign = 0);
void transceiveAsyncFinish(uint8_t irq);
uint8_t transceive(uint8_t *sendData, uint8_t sendLen, uint8_t *recvData, uint8_t *recvLen,
uint8_t validBits= 0, uint8_t rxAlign = 0, uint8_t *rxValidBits = nullptr);
static void detectAsyncCb(uint8_t ret, Mfrc522* reader, uint8_t* response, uint8_t responseLen, void* userData);
public:
uint8_t read(uint8_t addr);
void read(uint8_t addr, uint8_t* data, uint8_t datalen, uint8_t rxAlign = 0);
void write(uint8_t addr, uint8_t data);
void write(uint8_t addr, uint8_t* data, uint8_t datalen);
void updateBit(uint8_t addr, uint8_t bit, bool value);
static Serial* serial;
Mfrc522(SpiMaster* spi, ShiftReg<NFC_PORTS>* csReg, uint8_t csPin);
uint8_t calculateCrc(uint8_t *data, uint8_t length, uint16_t *result);
uint8_t wakeupTag(uint8_t* bufferATQA, uint8_t *bufferLen);
uint8_t selectTag(Uid *uid);
uint8_t getUid(Uid *uid);
void irq();
void setRf(bool on);
bool detectAsync(void (*tagEnterdCb)(Mfrc522*, void*) = nullptr, void* userData = nullptr);
void stopAsync();
bool cardPresent();
bool testFifo();
bool checkIrq(uint8_t *irq)
{
write(ComIrqReg, 0b01111111);
if(read(Status1Reg) & (1 << 4))
{
*irq = read(ComIrqReg);
return true;
}
return false;
}
static bool probe(SpiMaster* spi, ShiftReg<NFC_PORTS>* csReg, uint8_t csPin);
};