419 lines
8.5 KiB
C++
419 lines
8.5 KiB
C++
#include "spi.h"
|
|
#include "mfrc522.h"
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
MFRC522::MFRC522(volatile uchar cs_pin, volatile uchar *cs_port, volatile uchar reset_pin, volatile uchar *reset_port) {
|
|
this->cs_pin = cs_pin;
|
|
this->cs_port = cs_port;
|
|
this->reset_pin = reset_pin;
|
|
this->reset_port = reset_port;
|
|
*(cs_port-1) |= (1<<cs_pin);
|
|
*(cs_port) |= (1<<cs_pin);
|
|
*(reset_port-1) |= (1<<reset_pin);
|
|
|
|
|
|
}
|
|
|
|
void MFRC522::put(uchar addr, uchar val)
|
|
{
|
|
*cs_port &= ~(1<<cs_pin);
|
|
spi::transfer((addr<<1)&0x7E);
|
|
spi::transfer(val);
|
|
*cs_port |= (1<<cs_pin);
|
|
}
|
|
|
|
|
|
uchar MFRC522::get(uchar addr)
|
|
{
|
|
uchar val;
|
|
//spi::cs_low();
|
|
*cs_port &= ~(1<<cs_pin);
|
|
//address format: 1XXXXXX0
|
|
spi::transfer(((addr<<1)&0x7E) | 0x80);
|
|
val =spi::transfer(0x00);
|
|
//spi::cs_high();
|
|
*cs_port |= (1<<cs_pin);
|
|
return val;
|
|
}
|
|
|
|
|
|
void MFRC522::SetBitMask(uchar reg, uchar mask)
|
|
{
|
|
uchar tmp;
|
|
tmp = get(reg);
|
|
put(reg, tmp | mask); // set bit mask
|
|
}
|
|
|
|
|
|
|
|
void MFRC522::ClearBitMask(uchar reg, uchar mask)
|
|
{
|
|
uchar tmp;
|
|
tmp = get(reg);
|
|
put(reg, tmp & (~mask)); // clear bit mask
|
|
}
|
|
|
|
void MFRC522::AntennaOn(void)
|
|
{
|
|
uchar temp;
|
|
|
|
temp = get(TxControlReg);
|
|
if (!(temp & 0x03))
|
|
{
|
|
SetBitMask(TxControlReg, 0x03);
|
|
}
|
|
}
|
|
|
|
void MFRC522::AntennaOff(void)
|
|
{
|
|
ClearBitMask(TxControlReg, 0x03);
|
|
}
|
|
|
|
void MFRC522::Reset(void)
|
|
{
|
|
put(CommandReg, PCD_RESETPHASE);
|
|
}
|
|
|
|
void MFRC522::Init(void)
|
|
{
|
|
spi::init();
|
|
// NRSTPD_DDR |= (1<<NRSTPD_PIN);
|
|
// NRSTPD_PORT |= (1<<NRSTPD_PIN);
|
|
*reset_port &= ~(1<<reset_pin);
|
|
*reset_port |= (1<<reset_pin);
|
|
|
|
Reset();
|
|
|
|
//Timer: TPrescaler*TreloadVal/6.78MHz = 24ms
|
|
put(TModeReg, 0x8D); //Tauto=1; f(Timer) = 6.78MHz/TPreScaler
|
|
put(TPrescalerReg, 0x3E); //TModeReg[3..0] + TPrescalerReg
|
|
put(TReloadRegL, 30);
|
|
put(TReloadRegH, 0);
|
|
put(TxAutoReg, 0x40); //100%ASK
|
|
put(ModeReg, 0x3D); //CRC original value 0x6363 ???
|
|
|
|
AntennaOn(); // open antenna
|
|
}
|
|
uchar MFRC522::Request(uchar reqMode, uchar *TagType)
|
|
{
|
|
uchar status;
|
|
|
|
uint backBits; // bits of data received
|
|
put(BitFramingReg, 0x07); //TxLastBists = BitFramingReg[2..0] ???
|
|
|
|
TagType[0] = reqMode;
|
|
status = ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits);
|
|
|
|
if ((status != MI_OK) || (backBits != 0x10))
|
|
{
|
|
status = MI_ERR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
uchar MFRC522::ToCard(uchar command, uchar *sendData, uchar sendLen, uchar *backData, uint *backLen)
|
|
{
|
|
uchar status = MI_ERR;
|
|
uchar irqEn = 0x00;
|
|
|
|
uchar waitIRq = 0x00;
|
|
uchar lastBits;
|
|
uchar n;
|
|
uint i;
|
|
|
|
switch (command)
|
|
{
|
|
case PCD_AUTHENT: // card key authentication
|
|
{
|
|
irqEn = 0x12;
|
|
waitIRq = 0x10;
|
|
break;
|
|
}
|
|
case PCD_TRANSCEIVE: // send data in FIFO
|
|
{
|
|
irqEn = 0x77;
|
|
waitIRq = 0x30;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
put(CommIEnReg, irqEn|0x80); // permission for interrupt request
|
|
ClearBitMask(CommIrqReg, 0x80); // clear all bits of the interrupt request
|
|
SetBitMask(FIFOLevelReg, 0x80); //FlushBuffer=1, FIFO initialize
|
|
|
|
put(CommandReg, PCD_IDLE); //NO action; clear current command ???
|
|
|
|
// write data into FIFO
|
|
for (i=0; i<sendLen; i++)
|
|
{
|
|
put(FIFODataReg, sendData[i]);
|
|
}
|
|
|
|
// execute command
|
|
put(CommandReg, command);
|
|
if (command == PCD_TRANSCEIVE)
|
|
{
|
|
SetBitMask(BitFramingReg, 0x80); //StartSend=1,transmission of data starts
|
|
}
|
|
|
|
|
|
// wait for the completion of data transmission
|
|
i = 2000; // adjust i according to clock frequency, max wait time for M1 card operation 25ms ???
|
|
do
|
|
{
|
|
//CommIrqReg[7..0]
|
|
//Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq
|
|
n = get(CommIrqReg);
|
|
i--;
|
|
}
|
|
while ((i!=0) && !(n&0x01) && !(n&waitIRq));
|
|
|
|
ClearBitMask(BitFramingReg, 0x80); //StartSend=0
|
|
|
|
if (i != 0)
|
|
{
|
|
if(!(get(ErrorReg) & 0x1B)) //BufferOvfl Collerr CRCErr ProtecolErr
|
|
{
|
|
status = MI_OK;
|
|
if (n & irqEn & 0x01)
|
|
{
|
|
status = MI_NOTAGERR; //??
|
|
|
|
}
|
|
|
|
if (command == PCD_TRANSCEIVE)
|
|
{
|
|
n = get(FIFOLevelReg);
|
|
lastBits = get(ControlReg) & 0x07;
|
|
if (lastBits)
|
|
{
|
|
*backLen = (n-1)*8 + lastBits;
|
|
}
|
|
else
|
|
{
|
|
*backLen = n*8;
|
|
}
|
|
|
|
if (n == 0)
|
|
{
|
|
n = 1;
|
|
}
|
|
if (n > MAX_LEN)
|
|
|
|
{
|
|
n = MAX_LEN;
|
|
}
|
|
|
|
// read the data received in FIFO
|
|
for (i=0; i<n; i++)
|
|
{
|
|
backData[i] = get(FIFODataReg);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = MI_ERR;
|
|
}
|
|
|
|
}
|
|
|
|
//SetBitMask(ControlReg,0x80); //timer stops
|
|
//Write_MFRC522(CommandReg, PCD_IDLE);
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
uchar MFRC522::Anticoll(uchar *serNum)
|
|
{
|
|
uchar status;
|
|
uchar i;
|
|
uchar serNumCheck=0;
|
|
uint unLen;
|
|
|
|
put(BitFramingReg, 0x00); //TxLastBists = BitFramingReg[2..0]
|
|
|
|
serNum[0] = PICC_ANTICOLL;
|
|
serNum[1] = 0x20;
|
|
status = ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen);
|
|
|
|
if (status == MI_OK)
|
|
{
|
|
// verify card sequence number
|
|
for (i=0; i<4; i++)
|
|
{
|
|
|
|
serNumCheck ^= serNum[i];
|
|
}
|
|
if (serNumCheck != serNum[i])
|
|
{
|
|
status = MI_ERR;
|
|
}
|
|
}
|
|
|
|
//SetBitMask(CollReg, 0x80); //ValuesAfterColl=1
|
|
|
|
return status;
|
|
}
|
|
|
|
void MFRC522::CalulateCRC(uchar *pIndata, uchar len, uchar *pOutData)
|
|
{
|
|
uchar i, n;
|
|
|
|
ClearBitMask(DivIrqReg, 0x04); //CRCIrq = 0
|
|
SetBitMask(FIFOLevelReg, 0x80); // clear FIFO pointer
|
|
//Write_MFRC522(CommandReg, PCD_IDLE);
|
|
|
|
// write data into FIFO
|
|
for (i=0; i<len; i++)
|
|
{
|
|
put(FIFODataReg, *(pIndata+i));
|
|
}
|
|
put(CommandReg, PCD_CALCCRC);
|
|
|
|
// wait for completion of CRC calculation
|
|
i = 0xFF;
|
|
do
|
|
{
|
|
n = get(DivIrqReg);
|
|
i--;
|
|
}
|
|
while ((i!=0) && !(n&0x04)); //CRCIrq = 1
|
|
|
|
// read result from CRC calculation
|
|
pOutData[0] = get(CRCResultRegL);
|
|
pOutData[1] = get(CRCResultRegM);
|
|
}
|
|
|
|
|
|
uchar MFRC522::SelectTag(uchar *serNum)
|
|
{
|
|
uchar i;
|
|
uchar status;
|
|
uchar size;
|
|
uint recvBits;
|
|
uchar buffer[9];
|
|
|
|
//ClearBitMask(Status2Reg, 0x08); //MFCrypto1On=0
|
|
|
|
buffer[0] = PICC_SElECTTAG;
|
|
buffer[1] = 0x70;
|
|
for (i=0; i<5; i++)
|
|
{
|
|
buffer[i+2] = *(serNum+i);
|
|
}
|
|
CalulateCRC(buffer, 7, &buffer[7]); //??
|
|
status = ToCard(PCD_TRANSCEIVE, buffer, 9, buffer, &recvBits);
|
|
|
|
if ((status == MI_OK) && (recvBits == 0x18))
|
|
|
|
{
|
|
size = buffer[0];
|
|
}
|
|
else
|
|
{
|
|
size = 0;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
uchar MFRC522::Auth(uchar authMode, uchar BlockAddr, uchar *Sectorkey, uchar *serNum)
|
|
{
|
|
uchar status;
|
|
uint recvBits;
|
|
uchar i;
|
|
uchar buff[12];
|
|
|
|
// Verification instructions + block address + sector password + card sequence number
|
|
buff[0] = authMode;
|
|
buff[1] = BlockAddr;
|
|
for (i=0; i<6; i++)
|
|
{
|
|
buff[i+2] = *(Sectorkey+i);
|
|
}
|
|
for (i=0; i<4; i++)
|
|
{
|
|
buff[i+8] = *(serNum+i);
|
|
}
|
|
status = ToCard(PCD_AUTHENT, buff, 12, buff, &recvBits);
|
|
|
|
if ((status != MI_OK) || (!(get(Status2Reg) & 0x08)))
|
|
{
|
|
status = MI_ERR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
uchar MFRC522::Read(uchar blockAddr, uchar *recvData)
|
|
{
|
|
|
|
uchar status;
|
|
uint unLen;
|
|
|
|
recvData[0] = PICC_READ;
|
|
recvData[1] = blockAddr;
|
|
CalulateCRC(recvData,2, &recvData[2]);
|
|
status = ToCard(PCD_TRANSCEIVE, recvData, 4, recvData, &unLen);
|
|
|
|
if ((status != MI_OK) || (unLen != 0x90))
|
|
{
|
|
status = MI_ERR;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
uchar MFRC522::Write(uchar blockAddr, uchar *writeData)
|
|
{
|
|
uchar status;
|
|
uint recvBits;
|
|
uchar i;
|
|
uchar buff[18];
|
|
|
|
|
|
buff[0] = PICC_WRITE;
|
|
buff[1] = blockAddr;
|
|
CalulateCRC(buff, 2, &buff[2]);
|
|
status = ToCard(PCD_TRANSCEIVE, buff, 4, buff, &recvBits);
|
|
|
|
if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
|
|
{
|
|
status = MI_ERR;
|
|
}
|
|
|
|
if (status == MI_OK)
|
|
{
|
|
for (i=0; i<16; i++) // write 16Byte data into FIFO
|
|
{
|
|
buff[i] = *(writeData+i);
|
|
}
|
|
CalulateCRC(buff, 16, &buff[16]);
|
|
status = ToCard(PCD_TRANSCEIVE, buff, 18, buff, &recvBits);
|
|
|
|
if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A))
|
|
{
|
|
status = MI_ERR;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
char MFRC522::Halt(void)
|
|
{
|
|
uint unLen;
|
|
uchar buff[4];
|
|
|
|
buff[0] = PICC_HALT;
|
|
buff[1] = 0;
|
|
CalulateCRC(buff, 2, &buff[2]);
|
|
|
|
return ToCard(PCD_TRANSCEIVE, buff, 4, buff,&unLen);
|
|
} |