MFRC522讀卡封裝(附源代碼)

Mfrc.h

#ifndef _MFRC_H_
#define _MFRC_H_


#include "libreagent.h"


// 應答
#define SW_OK                   (0x9000)
#define SW_PCD                  (0x9870)

// 密鑰長度
#define KEY_LEN                 (8)
// 命令長度
#define LENGTH_OF_COMMAND       (64)


class REAGENT_EXPORT Mfrc
{
public:
    Mfrc();
    virtual ~Mfrc();

    // 尋試劑卡
    virtual quint16 request() = 0;

    // 認證(8位密鑰)
    quint16 authenticate(quint8 keyId, const quint8* key);

    // 讀寫文件
    quint16 readBinaryFile(quint8* content, int len, quint8 offset);
    quint16 writeBinaryFile(const quint8* content, int len, quint8 offset);

public:
    // 取隨機數(8字節)
    quint16 getChallenge(quint8* challenge);
    // 外部認證(8字節隨機數)
    quint16 externalAuthenticate(quint8 keyId, const quint8* challenge);
    // 卡片擦除
    quint16 erase();
    // 建立目錄
    quint16 createDfFile(quint16 fileId, quint16 size, quint8 appId);
    // 創建密鑰文件
    quint16 createKeyFile(quint16 fileId, quint16 size);
    // 創建二進制文件
    quint16 createBinaryFile(quint16 fileId, quint16 size);
    // 添加線路保護密鑰
    quint16 createLineProtectKey(quint8 keyId, const quint8* key);
    // 添加外部認證密鑰
    quint16 createExternalAuthenticateKey(quint8 keyId, const quint8* key);
    // 選中文件
    quint16 selectMfFile();
    quint16 selectFile(quint16 fileId);

protected:
    // 格式化
    QString toString(const quint8* datas, quint8 len);

    // 接收發送
    virtual quint16 piccTransceive(quint8* trans, quint8 tlen, quint8* recv, quint8& rlen) = 0;
};


#endif // _MFRC_H_

 

Mfrc.cpp

#include <QtCore/QtDebug>

#include "des.h"
#include "mfrc.h"
#include "fmcos.h"
#include "utility.h"


Mfrc::Mfrc()
{

}

Mfrc::~Mfrc()
{

}

// 認證(8位密鑰)
quint16 Mfrc::authenticate(quint8 keyId, const quint8* key)
{
    qDebug() << "Mfrc authenticate" << QString::number(keyId, 16);

    // 獲取隨機數
    quint8 challenge[KEY_LEN] = { 0 };

    quint16 ret = this->getChallenge(challenge);
    if (SW_OK == ret)
    {
        // 對隨機數進行DES加密
        quint8 encrypted[KEY_LEN] = { 0 };
        Des::encrypt(challenge, key, encrypted, KEY_LEN);

        // 外部認證(8字節隨機數)
        ret = this->externalAuthenticate(keyId, encrypted);
        if (SW_OK == ret)
        {

        }
        else
        {
            qWarning() << "Mfrc authenticate externalAuthenticate fail";
        }
    }
    else
    {
        qWarning() << "Mfrc authenticate getChallenge fail";
    }

    return ret;
}

// 讀寫文件
quint16 Mfrc::readBinaryFile(quint8* content, int len, quint8 offset)
{
    qDebug() << "Mfrc readBinaryFile" << QString::number(offset, 16) << QString::number(len, 16);

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::readBinrayCommand(buf, offset, len);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    quint16 ret = this->piccTransceive(buf, tlen, buf, rlen);

    if (SW_OK == ret)
    {
        // 返回隨機數(0A 01 84 8A 51 10 9E 2B A7 A2 90 00,跳過0A 01)
        memcpy(content, buf + 2, len);
    }

    return ret;
}

quint16 Mfrc::writeBinaryFile(const quint8* content, int len, quint8 offset)
{
    qDebug() << "Mfrc writeBinaryFile" << QString::number(offset, 16) << QString::number(len, 16);

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::writeBinaryCommand(buf, offset, content, len);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    return this->piccTransceive(buf, tlen, buf, rlen);
}

// 取隨機數(8字節)
quint16 Mfrc::getChallenge(quint8* challenge)
{
    qDebug() << "Mfrc getChallenge";

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::getChallengeCommand(buf, KEY_LEN);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    quint16 ret = this->piccTransceive(buf, tlen, buf, rlen);

    if (SW_OK == ret)
    {
        // 返回隨機數(0A 01 84 8A 51 10 9E 2B A7 A2 90 00,跳過0A 01)
        memcpy(challenge, buf + 2, KEY_LEN);
    }

    return ret;
}

// 外部認證(8字節隨機數)
quint16 Mfrc::externalAuthenticate(quint8 keyId, const quint8* challenge)
{
    qDebug() << "Mfrc externalAuthenticate" << QString::number(keyId, 16);

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::externalAuthenticateCommand(buf, keyId, challenge);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    return this->piccTransceive(buf, tlen, buf, rlen);
}

// 卡片擦除
quint16 Mfrc::erase()
{
    qDebug() << "Mfrc erase";

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::eraseCommand(buf);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    return this->piccTransceive(buf, tlen, buf, rlen);
}

// 建立目錄
quint16 Mfrc::createDfFile(quint16 fileId, quint16 size, quint8 appId)
{
    qDebug() << "Mfrc createDfFile" << QString::number(fileId, 16) << QString::number(size, 16) << QString::number(appId, 16);

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::createDfFileCommand(buf, fileId, size, appId);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    return this->piccTransceive(buf, tlen, buf, rlen);
}

// 創建密鑰文件
quint16 Mfrc::createKeyFile(quint16 fileId, quint16 size)
{
    qDebug() << "Mfrc createKeyFile" << QString::number(fileId, 16) << QString::number(size, 16);

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::createKeyFileCommand(buf, fileId, size);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    return this->piccTransceive(buf, tlen, buf, rlen);
}

// 創建二進制文件
quint16 Mfrc::createBinaryFile(quint16 fileId, quint16 size)
{
    qDebug() << "Mfrc createBinaryFile" << QString::number(fileId, 16) << QString::number(size, 16);

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::createBinaryFileCommand(buf, fileId, size);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    return this->piccTransceive(buf, tlen, buf, rlen);
}

// 添加線路保護密鑰
quint16 Mfrc::createLineProtectKey(quint8 keyId, const quint8* key)
{
    qDebug() << "Mfrc createLineProtectKey" << QString::number(keyId, 16);

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::writeLineKeyCommand(buf, keyId, key);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    return this->piccTransceive(buf, tlen, buf, rlen);
}

// 添加外部認證密鑰
quint16 Mfrc::createExternalAuthenticateKey(quint8 keyId, const quint8* key)
{
    qDebug() << "Mfrc createExternalAuthenticateKey" << QString::number(keyId, 16);

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::writeExternalKeyCommand(buf, keyId, key);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    return this->piccTransceive(buf, tlen, buf, rlen);
}

// 選中文件
quint16 Mfrc::selectMfFile()
{
    return this->selectFile(0x3F00);
}

quint16 Mfrc::selectFile(quint16 fileId)
{
    qDebug() << "Mfrc selectFile" << QString::number(fileId, 16);

    // 指令
    quint8 buf[LENGTH_OF_COMMAND] = { 0 };
    quint8 tlen = FMCos::selectFileCommand(buf, fileId);

    // 發送指令,接收返回值
    quint8 rlen = 0;
    return this->piccTransceive(buf, tlen, buf, rlen);
}

// 格式化
QString Mfrc::toString(const quint8* datas, quint8 len)
{
    QString text;

    for (int i = 0; i < len; i++)
    {
        text += QString("%1").arg(*(datas + i), 2, 16, QChar('0'));
    }

    return text;
}

 

Mfrc522.h

#ifndef _MFRC_522_H_
#define _MFRC_522_H_


#include "mfrc.h"

class Mfrc522Private;


class REAGENT_EXPORT Mfrc522 : public Mfrc
{
public:
    Mfrc522();
    virtual ~Mfrc522();

    // 尋試劑卡
    virtual quint16 request();

    // 通信設備
    void setSpi(const QString& dev);

protected:
    // 接收發送
    virtual quint16 piccTransceive(quint8* trans, quint8 tlen, quint8* recv, quint8& rlen);

private:
    // 芯片復位
    virtual quint16 reset();
    // 尋卡
    virtual quint16 request(quint16& type);
    // 防卡衝突
    virtual quint16 antiCollision(quint32& rfid);
    // 選卡
    virtual quint16 select(quint32 rfid);
    // 復位激活卡
    virtual quint16 rats();

private:
    Mfrc522Private* d;
};


#endif // _MFRC_522_H_

 

Mfrc522.cpp

#include <QtCore/QtDebug>

#include "spi.h"
#include "fmcos.h"
#include "mfrc522.h"
#include "utility.h"


// Command
#define Command_Idle            (0x00) // 取消當前命令
#define Command_CalcCrc         (0x03) // CRC計算
#define Command_Transceive      (0x0C) // 發送並接收數據
#define Command_ResetPhase      (0x0F) // 復位

// Reg
#define Reg_Command             (0x01) // 啓動和停止命令的執行
#define Reg_ComIEn              (0x02) // 中斷請求傳遞的使能和禁能控制位
#define Reg_DivIEn              (0x03)
#define Reg_ComIrq              (0x04) // 包含中斷請求標誌
#define Reg_DivIrq              (0x05)
#define Reg_Error               (0x06) // 錯誤標誌,指示執行的上個命令的錯誤狀態
#define Reg_Status1             (0x07) // 包含通信的狀態標誌
#define Reg_Status2             (0x08) // 包含接收器和發射器的狀態標誌
#define Reg_FifoData            (0x09) // 64字節FIFO緩衝區的輸入和輸出
#define Reg_FifoLevel           (0x0A) // 指示FIFO中存儲的字節數
#define Reg_Control             (0x0C) // 不同的控制寄存器
#define Reg_BitFraming          (0x0D) // 面向位的幀的調節
#define Reg_Coll                (0x0E)

#define Reg_Mode                (0x11) // 定義發送和接收的常用模式
#define Reg_TxMode              (0x12) // 定義發送過程的數據傳輸速率
#define Reg_RxMode              (0x13) // 定義接收過程中的數據傳輸速率
#define Reg_TxControl           (0x14) // 控制天線驅動器的設置
#define Reg_TxAuto              (0x15)
#define Reg_RxSel               (0x17) // 選擇內部的接收器設置

#define Reg_CRCResultH          (0x21) // 顯示CRC計算的實際值
#define Reg_CRCResultL             (0x22)
#define Reg_RFCfg               (0x26) // 配置接收器增益
#define Reg_TMode               (0x2A) // 定義內部定時器的設置
#define Reg_TPrescaler          (0x2B)
#define Reg_TReloadH            (0x2C) // 描述16位長的定時器重裝值
#define Reg_TReloadL            (0x2D)

#define Reg_Version             (0x37) // 顯示版本


class Mfrc522Private
{
public:
    Mfrc522Private();
    ~Mfrc522Private();

    // 等待IRQ
    bool waitComIrq();

    // Cmd
    bool writeCmd(quint8 data);

    // 是否出錯
    bool isError(quint8 mask);

    // 開關天線
    bool switchAntenna(bool on);

    // Fifo
    bool readFifo(quint8* data, int len);
    bool writeFifo(const quint8* data, int len);

    // Reg
    bool setMask(quint8 reg, quint8 mask);
    bool clearMask(quint8 reg, quint8 mask);
    bool waitMask(quint8 reg, quint8 mask, quint16 timeout);

    bool readReg(quint8 reg, quint8& data);
    bool writeReg(quint8 reg, quint8 data);

    bool readReg(quint8 lreg, quint8 hreg, quint16& data);
    bool writeReg(quint8 lreg, quint8 hreg, quint16 data);

    // 應答判定
    quint16 sw(const quint8* data, int len);

    // 計算CRC
    bool calcCrc1(quint8* data, int len);
    bool calcCrc2(quint8* data, int len);

    // 接收發送
    bool receive(quint8* recv, quint8& rlen);
    bool trans(const quint8* trans, quint8 tlen);
    quint16 pcdTransceive(quint8* trans, quint8 tlen, quint8* recv, quint8& rlen);

public:
    // 通信設備
    QString dev;
};

Mfrc522Private::Mfrc522Private()
    : dev()
{

}

Mfrc522Private::~Mfrc522Private()
{

}

// 等待IRQ
bool Mfrc522Private::waitComIrq()
{
    // 注意:30ms超時不能隨便更改,更改後可能導致讀卡外部認證時出錯
    return this->waitMask(Reg_ComIrq, 0x30, 30);
}

// Cmd
bool Mfrc522Private::writeCmd(quint8 data)
{
    return this->writeReg(Reg_Command, data);
}

// 是否出錯
bool Mfrc522Private::isError(quint8 mask)
{
    bool ret = true;

    // ErrorReg : Error bit register showing the error status of the last command executed.
    quint8 err = 0xFF;
    if (this->readReg(Reg_Error, err))
    {
        ret = (err & mask);
    }

    return ret;
}

// 開關天線
bool Mfrc522Private::switchAntenna(bool on)
{
    quint8 addr = Reg_TxControl;
    if (on)
    {
        return this->setMask(addr, 3);
    }
    else
    {
        return this->clearMask(addr, 3);
    }
}

// Fifo
bool Mfrc522Private::readFifo(quint8* data, int len)
{
    for (int i = 0; i < len; i++)
    {
        if (!this->readReg(Reg_FifoData, *(data + i)))
        {
            return false;
        }
    }
    return true;
}

bool Mfrc522Private::writeFifo(const quint8* data, int len)
{
    for (int i = 0; i < len; i++)
    {
        if (!this->writeReg(Reg_FifoData, *(data + i)))
        {
            return false;
        }
    }
    return true;
}

// Reg
bool Mfrc522Private::setMask(quint8 reg, quint8 mask)
{
    quint8 data = 0;
    if (this->readReg(reg, data))
    {
        data |= mask;
        if (this->writeReg(reg, data))
        {
            return true;
        }
    }
    return false;
}

bool Mfrc522Private::clearMask(quint8 reg, quint8 mask)
{
    quint8 data = 0;
    if (this->readReg(reg, data))
    {
        data &= ~mask;
        if (this->writeReg(reg, data))
        {
            return true;
        }
    }
    return false;
}

bool Mfrc522Private::waitMask(quint8 reg, quint8 mask, quint16 timeout)
{
    bool ret = false;

    // 延時
    Utility::msleep(timeout);

    // 讀值
    quint8 data = 0;
    if (this->readReg(reg, data))
    {
        if (data & mask)
        {
            ret = true;
        }
    }

    return ret;
}

bool Mfrc522Private::readReg(quint8 reg, quint8& data)
{
    // 參見手冊:10.2.4章節
    quint8 rreg = (0x80 | ((reg << 1) & 0x7E));
    return Spi::read1(this->dev, rreg, data);
}

bool Mfrc522Private::writeReg(quint8 reg, quint8 data)
{
    // 參見手冊:10.2.4章節
    quint8 wreg = ((reg << 1) & 0x7E);
    return Spi::write1(this->dev, wreg, data);
}

bool Mfrc522Private::readReg(quint8 lreg, quint8 hreg, quint16& data)
{
    bool ret = false;

    quint8 d[2] = { 0 };
    if (this->readReg(lreg, d[0]) && this->readReg(hreg, d[1]))
    {
        data = ((d[1] << 8) | d[0]);
        ret = true;
    }

    return ret;
}

bool Mfrc522Private::writeReg(quint8 lreg, quint8 hreg, quint16 data)
{
    return (this->writeReg(lreg, (data & 0xFF)) && this->writeReg(hreg, ((data >> 8) & 0xFF)));
}

// 應答判定
quint16 Mfrc522Private::sw(const quint8* data, int len)
{
    // 0a 01 d7 1d b9 8f c8 29 3d f6 90 00 3b e6
    const quint8* p = data + len - 4;
    return ((*p << 8) | *(p + 1));
}

// 計算CRC
bool Mfrc522Private::calcCrc1(quint8* data, int len)
{
    bool ret = false;

    do
    {
        // DivIRqReg : Contains Interrupt Request bits
        if (!this->clearMask(Reg_DivIrq, 0x04))
        {
            break;
        }

        // Idle : No action; cancels current command execution.
        if (!this->writeCmd(Command_Idle))
        {
            break;
        }

        // FIFOLevelReg : Indicates the number of bytes stored in the FIFO.
        if (!this->setMask(Reg_FifoLevel, 0x80))
        {
            break;
        }

        // FIFODataReg : Input and output of 64 byte FIFO buffer.
        if (!this->writeFifo(data, len))
        {
            break;
        }

        // CalcCRC : Activates the CRC co - processor or performs a selftest.
        if (!this->writeCmd(Command_CalcCrc))
        {
            break;
        }

        // DivIrqReg : Contains Interrupt Request bits
        // bit2 : Set to logic 1, when the CRC command is active and all data are processed.
        if (!this->waitMask(Reg_DivIrq, 0x04, 10))
        {
            break;
        }

        // CRCResultReg : Shows the actual MSB and LSB values of the CRC calculation.
        quint16 crc = 0;
        if (!this->readReg(Reg_CRCResultL, Reg_CRCResultH, crc))
        {
            break;
        }

        data[len] = (crc & 0xFF);
        data[len + 1] = ((crc >> 8) & 0xFF);

        ret = true;
    } while (0);

    return ret;
}

bool Mfrc522Private::calcCrc2(quint8* data, int len)
{
    quint8 crc = 0;

    for (int i = 0; i < len; i++)
    {
        crc ^= *(data + i);
    }

    *(data + len) = crc;

    return true;
}

// 接收發送
bool Mfrc522Private::receive(quint8* recv, quint8& rlen)
{
    bool ret = false;

    do
    {
        // BitFramingReg : Adjustments for bit oriented frames.
        if (!this->clearMask(Reg_BitFraming, 0x80))
        {
            break;
        }

        // ErrorReg : Error bit register showing the error status of the last command executed.
        // WrErr TempErr * BufferOvfl CollErr CRCErr ParityErr ProtocolErr
        if (this->isError(0x1B))
        {
            break;
        }

        // FIFOLevelReg : Indicates the number of bytes stored in the FIFO.
        quint8 bytes = 0;
        if (!this->readReg(Reg_FifoLevel, bytes))
        {
            break;
        }

        // ControlReg : Miscellaneous control bits.
        // bit2 - bit0 : RxLastBits Shows the number of valid bits in the last received byte. If 0, the whole byte is valid.
        quint8 control = 0;
        if (!this->readReg(Reg_Control, control))
        {
            break;
        }

        // 讀FIFO數據
        if (!this->readFifo(recv, bytes))
        {
            break;
        }

        ret = true;
        rlen = bytes;
    } while (0);

    return ret;
}

bool Mfrc522Private::trans(const quint8* trans, quint8 tlen)
{
    bool ret = false;

    do
    {
        // ComlEnReg : Controls bits to enable and disable the passing of Interrupt Requests
        // bit7 - bit0 : IRqInv TxIEn RxIEn IdleIEn HiAlertIEn LoAlertIEn ErrIEn TimerIEn
        if (!this->writeReg(Reg_ComIEn, 0xF7))
        {
            break;
        }

        // CommIRqReg : Contains Interrupt Request bits.
        // bit7 - bit0 : Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq
        if (!this->clearMask(Reg_ComIrq, 0x80))
        {
            break;
        }

        // FIFOLevelReg : Indicates the number of bytes stored in the FIFO.
        // bit7 : this bit clears the internal FIFO-buffer's read and write pointer and the bit BufferOvfl in the register ErrReg immediately.
        // bit6 - bit0 : Indicates the number of bytes stored in the FIFO buffer.
        if (!this->setMask(Reg_FifoLevel, 0x80))
        {
            break;
        }

        // Idle : No action; cancels current command execution.
        if (!this->writeCmd(Command_Idle))
        {
            break;
        }

        // FIFODataReg : Input and output of 64 byte FIFO buffer.
        if (!this->writeFifo(trans, tlen))
        {
            break;
        }

        // Transceive : Transmits data from FIFO buffer to the antenna and activates automatically the receiver after transmission.
        if (!this->writeCmd(Command_Transceive))
        {
            break;
        }

        // BitFramingReg : Adjustments for bit oriented frames.
        if (!this->setMask(Reg_BitFraming, 0x80))
        {
            break;
        }

        ret = true;
    } while (0);

    return ret;
}

quint16 Mfrc522Private::pcdTransceive(quint8* trans, quint8 tlen, quint8* recv, quint8& rlen)
{
    quint16 ret = SW_PCD;

    do
    {
        // trans
        if (!this->trans(trans, tlen))
        {
            break;
        }

        // wait irq
        if (!this->waitComIrq())
        {
            break;
        }

        // receive
        if (!this->receive(recv, rlen))
        {
            break;
        }

        ret = SW_OK;
    } while (0);

    return ret;
}


Mfrc522::Mfrc522()
    : Mfrc(), d(new Mfrc522Private())
{

}

Mfrc522::~Mfrc522()
{
    delete d;
}

// 通信設備
void Mfrc522::setSpi(const QString& dev)
{
    d->dev = dev;
}

// 尋試劑卡
quint16 Mfrc522::request()
{
    quint16 ret = SW_PCD;

    do
    {
        // 復位
        ret = this->reset();
        if (SW_OK != ret)
        {
            qWarning() << "Mfrc522 request reset fail";
            break;
        }

        // 尋卡
        quint16 type = 0;
        ret = this->request(type);
        if (SW_OK != ret)
        {
            qWarning() << "Mfrc522 request request fail";
            break;
        }

        // 防衝突
        quint32 rfid = 0;
        ret = this->antiCollision(rfid);
        if (SW_OK != ret)
        {
            qWarning() << "Mfrc522 request antiCollision fail";
            break;
        }

        // 選卡
        ret = this->select(rfid);
        if (SW_OK != ret)
        {
            qWarning() << "Mfrc522 request select fail";
            break;
        }

        // 復位激活CPU卡
        ret = this->rats();
        if (SW_OK != ret)
        {
            qWarning() << "Mfrc522 request select fail";
            break;
        }

        ret = SW_OK;
    } while (0);

    return ret;
}

// 芯片復位
quint16 Mfrc522::reset()
{
    quint16 ret = SW_PCD;

    qDebug() << "Mfrc522 reset";

    do
    {
        // SoftReset : Resets the MFRC522
        if (!d->writeCmd(Command_ResetPhase))
        {
            break;
        }

        Utility::msleep(100);

        // VersionReg : Shows the version
        quint8 version;
        if (!d->readReg(Reg_Version, version))
        {
            break;
        }

        // TModeReg : Defines settings for the internal timer
        // TPrescalerReg : Defines settings for the internal timer
        if (!d->writeReg(Reg_TMode, 141) || !d->writeReg(Reg_TPrescaler, 62))
        {
            break;
        }

        // TReloadReg : Describes the 16 bit timer reload value
        if (!d->writeReg(Reg_TReloadL, Reg_TReloadH, 30))
        {
            break;
        }

        // ModeReg : Defines general mode settings for transmitting and receiving.
        // TxASKReg : Controls the setting of the TX modulation
        if (!d->writeReg(Reg_TxAuto, 64) || !d->writeReg(Reg_Mode, 61))
        {
            qWarning() << "Mfrc522 reset writeReg 64 61 fail";
            break;
        }

        Utility::msleep(10);

        // switch antenna on
        if (!d->switchAntenna(false))
        {
            break;
        }

        Utility::msleep(10);

        // switch antenna on
        if (!d->switchAntenna(true))
        {
            break;
        }

        ret = SW_OK;
    } while (0);

    return ret;
}

// 尋卡(成功返回卡片類型)
quint16 Mfrc522::request(quint16& type)
{
    quint16 ret = SW_PCD;

    qDebug() << "Mfrc522 request";

    do
    {
        // BitFramingReg : Adjustments for bit oriented frames
        if (!d->writeReg(Reg_BitFraming, 0x07))
        {
            break;
        }

        // PCD初始化
        FMCos::pcbInit();

        // 發送接收數據
        quint8 rlen;
        quint8 buf[LENGTH_OF_COMMAND] = { 0x26 }; // 尋未進入休眠狀態的卡

        ret = d->pcdTransceive(buf, 1, buf, rlen);
        if (SW_OK == ret)
        {
            // 返回卡類型
            type = (buf[0] | (buf[1] << 8));
        }

        qDebug() << "Mfrc522 request" << QString::number(type, 16);
    } while (0);

    return ret;
}

// 防卡衝突(成功返回卡片標識號)
quint16 Mfrc522::antiCollision(quint32& rfid)
{
    quint16 ret = SW_PCD;

    qDebug() << "Mfrc522 antiCollision";

    do
    {
        // BitFramingReg : Adjustments for bit oriented frames
        if (!d->writeReg(Reg_BitFraming, 0x00))
        {
            break;
        }

        // 發送接收數據
        quint8 rlen;
        quint8 buf[LENGTH_OF_COMMAND] = { 0x93, 0x20 };

        ret = d->pcdTransceive(buf, 2, buf, rlen);
        if (SW_OK == ret)
        {
            // 返回卡號
            rfid = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
        }
    } while (0);

    return ret;
}

// 選卡
quint16 Mfrc522::select(quint32 rfid)
{
    quint16 ret = SW_PCD;

    qDebug() << "Mfrc522 select" << QString::number(rfid, 16);

    do 
    {
        quint8 buf[LENGTH_OF_COMMAND] = { 0x93, 0x70, (quint8)(rfid >> 24), (quint8)(rfid >> 16), (quint8)(rfid >> 8), (quint8)rfid, 0x00 };

        // CRC校驗
        if (!d->calcCrc2(&buf[2], 4))
        {
            break;
        }
        if (!d->calcCrc1(buf, 7))
        {
            break;
        }

        // 發送接收
        quint8 rlen;
        ret = d->pcdTransceive(buf, 9, buf, rlen);
    } while (0);

    return ret;
}

// 復位激活卡
quint16 Mfrc522::rats()
{
    quint16 ret = SW_PCD;

    qDebug() << "Mfrc522 rats";

    do
    {
        quint8 buf[LENGTH_OF_COMMAND] = { 0xE0, 0x51 };
        
        // CRC校驗
        if (!d->calcCrc1(buf, 2))
        {
            break;
        }

        // 發送接收
        quint8 rlen;
        ret = d->pcdTransceive(buf, 4, buf, rlen);
    } while (0);

    return ret;
}

// 接收發送
quint16 Mfrc522::piccTransceive(quint8* trans, quint8 tlen, quint8* recv, quint8& rlen)
{
    quint16 ret = SW_PCD;

    do
    {
        // CRC校驗
        if (!d->calcCrc1(trans, tlen))
        {
            break;
        }

        // trans
        if (!d->trans(trans, tlen + 2))
        {
            break;
        }

        // output
        QString text = this->toString(trans, tlen + 2);
        qDebug() << "Mfrc522 piccTransceive trans" << text;

        // 取消次
        // Utility::msleep(30);

        // wait irq
        if (!d->waitComIrq())
        {
            break;
        }

        // receive
        if (!d->receive(recv, rlen))
        {
            break;
        }

        // output
        text = this->toString(recv, rlen);
        qDebug() << "Mfrc522 piccTransceive recv" << text;

        // check
        ret = d->sw(recv, rlen);
    } while (0);

    return ret;
}

 

FmCos相關接口參見

https://blog.csdn.net/calm_agan/article/details/86660179

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章