This commit is contained in:
lmx
2025-11-24 16:33:33 +08:00
parent eb9de783ed
commit e19ac5ad00
73 changed files with 2673 additions and 15087 deletions

View File

@ -0,0 +1,89 @@
#ifndef CPU_CARD_H
#define CPU_CARD_H 1
#include "rfid_main.h" // 包含 transmission_struct 的定义
/**
* @brief 存储ATS (Answer to Select) 信息的结构体
*/
struct ATS_STR
{
unsigned char Length; /**< ATS数据长度 */
unsigned char Ats_Data[255]; /**< ATS数据缓冲区 */
};
/**
* @brief 存储PPS (Protocol and Parameter Selection) 信息的结构体
*/
struct PPS_STR
{
unsigned char Length; /**< PPS数据长度 */
unsigned char Pps_Data[1]; /**< PPS数据缓冲区 */
};
/**
* @brief 存储CPU卡通信参数的结构体
*/
struct CPU_CARD_STR
{
unsigned char FSCI; /**< Frame Size for proximity coupling Integer */
unsigned char FSC; /**< Frame Size for proximity coupling (in bytes) */
unsigned char FWI; /**< Frame Waiting time Integer */
unsigned int FWT; /**< Frame Waiting Time (in ms) */
unsigned char SFGI; /**< Start-up Frame Guard time Integer */
unsigned char TA; /**< TA(1) parameter from ATS */
unsigned char TB; /**< TB(1) parameter from ATS */
unsigned char TC; /**< TC(1) parameter from ATS */
unsigned char PCB; /**< Protocol Control Byte */
unsigned char WTXM; /**< Waiting Time eXtension Multiplier */
struct ATS_STR ATS; /**< ATS信息 */
struct PPS_STR PPS; /**< PPS信息 */
};
extern struct CPU_CARD_STR CPU_CARD;
/**
* @brief 解析ATS (Answer to Select) 数据。
* @param ats_len [in] ATS数据的长度。
* @param ats [in] 指向ATS数据的指针。
* @return 操作状态SUCCESS表示成功。
*/
extern unsigned char Ats_Process( unsigned char ats_len, unsigned char *ats );
/**
* @brief CPU卡事件处理函数示例
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
extern unsigned char CPU_CARD_EVENT( void );
/**
* @brief 封装了重试逻辑的TPDU传输函数。
* @param tpdu [in, out] 指向传输结构体的指针。
* @return 操作状态。
*/
extern unsigned char CPU_TPDU( transmission_struct *tpdu );
/**
* @brief 发送RATS (Request for Answer to Select) 命令。
* @param ats_len [out] 指向用于存储ATS长度的变量的指针。
* @param ats [out] 指向用于存储ATS数据的缓冲区的指针。
* @return 操作状态SUCCESS表示成功。
*/
extern unsigned char CPU_Rats( unsigned char *ats_len, unsigned char *ats );
/**
* @brief 发送NAK (Negative Acknowledge) 响应。
* @param tpdu [in, out] 指向传输结构体的指针。
* @return 操作状态。
*/
extern unsigned char CPU_NAK( transmission_struct *tpdu );
/**
* @brief 发送APDU (Application Protocol Data Unit) 命令。
* @param apdu [in, out] 指向传输结构体的指针包含APDU命令和响应。
* @return 操作状态。
*/
extern unsigned char CPU_APDU( transmission_struct *apdu );
#endif

View File

@ -0,0 +1,97 @@
#ifndef _MIFARE_H_
#define _MIFARE_H_
// 定义Mifare认证密钥类型
#define KEY_A_M1 0
#define KEY_B_M1 1
// 声明全局变量
extern unsigned char SECTOR,BLOCK,BLOCK_NUM;
extern unsigned char BLOCK_DATA[16];
extern unsigned char KEY_A[16][6];
extern unsigned char KEY_B[16][6];
/**
* @brief Mifare卡事件处理函数示例
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
extern unsigned char MIFARE_CARD_EVENT(void);
/**
* @brief 清除Mifare卡加密认证标志。
* @return 无。
*/
extern void Mifare_Clear_Crypto(void);
/**
* @brief 将6字节的Mifare密钥加载到芯片的密钥缓冲区。
* @param mifare_key [in] 指向6字节密钥数组的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char Mifare_LoadKey(unsigned char *mifare_key);
/**
* @brief 执行Mifare卡的传输Transfer命令。
* @param block [in] 块号。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
extern unsigned char Mifare_Transfer(unsigned char block);
/**
* @brief 执行Mifare卡的恢复Restore命令。
* @param block [in] 块号。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
extern unsigned char Mifare_Restore(unsigned char block);
/**
* @brief 将4字节数据格式化为Mifare值块格式并写入指定块。
* @param block [in] 目标块号。
* @param data_buff [in] 指向4字节源数据的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
extern unsigned char Mifare_Blockset(unsigned char block,unsigned char *data_buff);
/**
* @brief 对Mifare卡的指定值块执行增值操作。
* @param block [in] 值块的块号。
* @param data_buff [in] 指向4字节增值数据的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
extern unsigned char Mifare_Blockinc(unsigned char block,unsigned char *data_buff);
/**
* @brief 对Mifare卡的指定值块执行减值操作。
* @param block [in] 值块的块号。
* @param data_buff [in] 指向4字节减值数据的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
extern unsigned char Mifare_Blockdec(unsigned char block,unsigned char *data_buff);
/**
* @brief 向Mifare卡写入一个16字节的数据块。
* @param block [in] 要写入的块号 (0x00 - 0x3F)。
* @param data_buff [in] 指向16字节数据的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
extern unsigned char Mifare_Blockwrite(unsigned char block,unsigned char *data_buff);
/**
* @brief 从Mifare卡读取一个16字节的数据块。
* @param block [in] 要读取的块号 (0x00 - 0x3F)。
* @param data_buff [out] 指向16字节缓冲区的指针用于存储读取的数据。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
extern unsigned char Mifare_Blockread(unsigned char block,unsigned char *data_buff);
/**
* @brief 对Mifare Classic卡片的指定扇区进行认证。
* @param key_mode [in] 认证模式,`KEY_A_M1` (0) 表示使用密钥A`KEY_B_M1` (1) 表示使用密钥B。
* @param sector [in] 要认证的扇区号 (0-15)。
* @param mifare_key [in] 指向6字节认证密钥的指针。
* @param card_uid [in] 指向4字节卡片UID的指针。
* @return 操作状态SUCCESS表示认证成功FAIL表示失败。
*/
extern unsigned char Mifare_Auth(unsigned char key_mode,unsigned char sector,unsigned char *mifare_key,unsigned char *card_uid);
#endif

View File

@ -0,0 +1,8 @@
#ifndef _NTAG_H
#define _NTAG_H
extern unsigned char PAGE_DATA[16];
extern unsigned char NTAG_EVENT(void);
extern unsigned char Read_Page(unsigned char page_num,unsigned char *page_data);
extern unsigned char Write_Page(unsigned char page_num,unsigned char *page_data);
#endif

View File

@ -0,0 +1,153 @@
/********************************************************************************************************
* @file READER.h
* @brief RFID 读卡器底层驱动及协议头文件
* @details
* 本文件定义了与RFID芯片交互所需的常量、数据结构和函数原型。
*
* @author Kilo Code
* @date 2025-11-24
* @version 1.0
********************************************************************************************************/
#ifndef _READER_H
#define _READER_H
/********************************************************************************************************
* 常量定义
********************************************************************************************************/
// ISO14443A 命令码
static const unsigned char RF_CMD_REQA = 0x26; /**< 请求命令 */
static const unsigned char RF_CMD_WUPA = 0x52; /**< 唤醒命令 */
static const unsigned char RF_CMD_ANTICOLL[3] = {0x93, 0x95, 0x97}; /**< 防冲突命令,根据级联级别选择 */
static const unsigned char RF_CMD_SELECT[3] = {0x93, 0x95, 0x97}; /**< 选择命令,根据级联级别选择 */
// MIFARE Classic 命令码
static const unsigned char RF_CMD_KEYA = 0x60; /**< 密钥A认证 */
static const unsigned char RF_CMD_KEYB = 0x61; /**< 密钥B认证 */
/********************************************************************************************************
* 卡片信息结构体
********************************************************************************************************/
/**
* @brief 存储ISO/IEC 14443 Type B卡片信息的结构体
*/
struct picc_b_struct
{
unsigned char ATQB[12]; /**< REQB/WUPB的响应 (Answer to Request B) */
unsigned char PUPI[4]; /**< Pseudo-Unique PICC Identifier */
unsigned char APPLICATION_DATA[4]; /**< 应用数据 */
unsigned char PROTOCOL_INF[3]; /**< 协议信息 */
unsigned char CID; /**< 卡片ID (Card Identifier) */
unsigned char Answer_to_HALT[1]; /**< HALT命令的响应 */
unsigned char SN[8]; /**< 序列号 (自定义命令获取) */
};
extern struct picc_b_struct PICC_B;
/**
* @brief 存储ISO/IEC 14443 Type A卡片信息的结构体
*/
struct picc_a_struct
{
unsigned char ATQA[2]; /**< REQA/WUPA的响应 (Answer to Request A) */
unsigned char CASCADE_LEVEL; /**< 当前级联级别 (用于处理多级UID) */
unsigned char UID_Length; /**< UID的长度 (4, 7, or 10 bytes) */
unsigned char UID[15]; /**< 卡片唯一ID (Unique Identifier) */
unsigned char BCC[3]; /**< 块校验字符 (Block Check Character) */
unsigned char SAK[3]; /**< 选择确认 (Select Acknowledge) */
};
extern struct picc_a_struct PICC_A;
/**
* @brief 存储ISO/IEC 15693 (Type V) 卡片信息的结构体
*/
struct picc_v_struct
{
unsigned char UID[8]; /**< 卡片唯一ID (Unique Identifier) */
unsigned char RESPONSE; /**< 命令响应标志 */
unsigned char BLOCK_DATA[4]; /**< 读取或写入的块数据 */
};
extern struct picc_v_struct PICC_V;
/**
* @brief 存储FeliCa (Type F) 卡片信息的结构体
*/
struct picc_f_struct
{
unsigned char UID[8]; /**< 卡片唯一ID (Unique Identifier) */
};
extern struct picc_f_struct PICC_F;
/********************************************************************************************************
* 芯片参数配置
********************************************************************************************************/
// --- Type A 参数 ---
#define GAIN_A 7 // 接收增益 (范围 0~7)
#define HPCF_A 3 // 高通滤波器截止频率 (范围 0~7)
#define AMPLITUDE_A 255 // RF场幅度 (范围 0~255)
// --- Type B 参数 ---
#define GAIN_B 7 // 接收增益
#define HPCF_B 3 // 高通滤波器截止频率
#define AMPLITUDE_B 255 // RF场幅度
#define MODULATION_B 100 // 调制深度 (范围 0~255, 值越小调制越深)
// --- Type V (ISO15693) 参数 ---
#define GAIN_V 7 // 接收增益
#define HPCF_V 4 // 高通滤波器截止频率
#define AMPLITUDE_V 255 // RF场幅度
#define MODULATION_V 10 // 调制深度
// --- Type F (FeliCa) 参数 ---
#define GAIN_F 7 // 接收增益
#define HPCF_F 4 // 高通滤波器截止频率
#define AMPLITUDE_F 255 // RF场幅度
#define MODULATION_F 100 // 调制深度
/********************************************************************************************************
* 函数原型声明
********************************************************************************************************/
// --- 通用函数 ---
extern void ModifyReg(unsigned char reg_address, unsigned char mask, unsigned char set);
extern void Clear_FIFO(void);
extern unsigned char SetCommand(unsigned char command);
extern void SetParity(unsigned char state);
extern void SetTimer(unsigned int timeout);
extern unsigned char SetCW(unsigned char mode);
// --- 协议初始化函数 ---
extern unsigned char ReaderA_Initial(void);
extern unsigned char ReaderB_Initial(void);
extern unsigned char ReaderV_Initial(void);
extern unsigned char ReaderF_Initial(void);
// --- Type A 命令 ---
extern unsigned char ReaderA_Wakeeup(struct picc_a_struct *picc_a);
extern unsigned char ReaderA_Request(struct picc_a_struct *picc_a);
extern unsigned char ReaderA_Anticoll(struct picc_a_struct *picc_a);
extern unsigned char ReaderA_Select(struct picc_a_struct *picc_a);
extern unsigned char ReaderA_CardActivate(struct picc_a_struct *picc_a);
// --- Type B 命令 ---
extern unsigned char ReaderB_Wakeup(struct picc_b_struct *picc_b);
extern unsigned char ReaderB_Request(struct picc_b_struct *picc_b);
extern unsigned char ReaderB_Attrib(struct picc_b_struct *picc_b);
extern unsigned char ReaderB_Halt(struct picc_b_struct *picc_b);
extern unsigned char ReaderB_Get_SN(struct picc_b_struct *picc_b);
// --- Type V (ISO15693) 命令 ---
extern unsigned char ReaderV_Inventory(struct picc_v_struct *picc_v);
extern unsigned char ReaderV_Select(struct picc_v_struct *picc_v);
extern unsigned char ReaderV_ReadSingleBlock(unsigned char block_num, struct picc_v_struct *picc_v);
extern unsigned char ReaderV_WriteSingleBlock(unsigned char block_num, struct picc_v_struct *picc_v);
// --- Type F (FeliCa) 命令 ---
extern unsigned char ReaderF_Inventory(struct picc_f_struct *picc_f);
#endif // _READER_H

View File

@ -0,0 +1,478 @@
/*********************************************************************
* *
* Copyright (c) 2010 Shanghai FuDan MicroElectronic Inc, Ltd. *
* All rights reserved. Licensed Software Material. *
* *
* Unauthorized use, duplication, or distribution is strictly *
* prohibited by law. *
* *
**********************************************************************/
#ifndef _READER_REG_H
#define _READER_REG_H
#define REG_COMMAND 0x00 //
#define REG_HOSTCTRL 0x01 //
#define REG_FIFOCONTROL 0x02 //
#define REG_WATERLEVEL 0x03 //
#define REG_FIFOLENGTH 0x04 //
#define REG_FIFODATA 0x05 //
#define REG_IRQ0 0x06 //
#define REG_IRQ1 0x07 //
#define REG_IRQ0EN 0x08 //
#define REG_IRQ1EN 0x09 //
#define REG_ERROR 0x0A //
#define REG_STATUS 0x0B //
#define REG_RXBITCTRL 0x0C //
#define REG_RXCOLL 0x0D //
#define REG_TCONTROL 0x0E //
#define REG_T0CONTROL 0x0F //
#define REG_T0RELOADHI 0x10 //
#define REG_T0RELOADLO 0x11 //
#define REG_T0COUNTERVALHI 0x12 //
#define REG_T0COUNTERVALLO 0x13 //
#define REG_T1CONTROL 0x14 //
#define REG_T1RELOADHI 0x15 //
#define REG_T1RELOADLO 0x16 //
#define REG_T1COUNTERVALHI 0x17 //
#define REG_T1COUNTERVALLO 0x18 //
#define REG_T2CONTROL 0x19 //
#define REG_T2RELOADHI 0x1A //
#define REG_T2RELOADLO 0x1B //
#define REG_T2COUNTERVALHI 0x1C //
#define REG_T2COUNTERVALLO 0x1D //
#define REG_T3CONTROL 0x1E //
#define REG_T3RELOADHI 0x1F //
#define REG_T3RELOADLO 0x20 //
#define REG_T3COUNTERVALHI 0x21 //
#define REG_T3COUNTERVALLO 0x22 //
#define REG_T4CONTROL 0x23 //
#define REG_T4RELOADHI 0x24 //
#define REG_T4RELOADLO 0x25 //
#define REG_T4COUNTERVALHI 0x26 //
#define REG_T4COUNTERVALLO 0x27 //
#define REG_TXMODE 0x28
#define REG_TXAMP 0x29
#define REG_TXCON 0x2A //
#define REG_TXI 0x2B //
#define REG_TXCRCCON 0x2C //
#define REG_RXCRCCON 0x2D //
#define REG_TXDATANUM 0x2E
#define REG_TXMODWIDTH 0x2F //
#define REG_TXSYM10BURSTLEN 0x30 //
#define REG_TXWAITCTRL 0x31 //
#define REG_TXWAITLO 0x32 //
#define REG_FRAMECON 0x33 //
#define REG_RXSOFD 0x34 //
#define REG_RXCTRL 0x35 //
#define REG_RXWAIT 0x36 //
#define REG_RXTHRESHOLD 0x37 //
#define REG_RCV 0x38 //
#define REG_RXANA 0x39 //
#define REG_LPCD_OPTIONS 0x3A //
#define REG_SERIALSPEED 0x3B //
#define REG_LFO_TRIMM 0x3C //
#define REG_CLKOUT_CTRL 0x3D //
#define REG_LPCD_THRESHOLD 0x3E //
#define REG_LPCD_QMIN 0x3F //
#define REG_LPCD_QMAX 0x40
#define REG_LPCD_IMIN 0x41
#define REG_LPCD_RESULT_I 0x42
#define REG_LPCD_RESULT_Q 0x43
#define REG_THNADJ 0x5F
#define REG_THNSET 0x61
#define REG_THNMIN 0x62
#define REG_DSP_CTRL1 0x64
#define REG_MISC 0x75
#define REG_RXTXCON 0x77
#define REG_ERROREXT 0x7E
#define REG_VERSION 0x7F
#define CMD_MASK 0x1F
#define CMD_IDLE 0x00
#define CMD_LPCD 0x01
#define CMD_LOADKEY 0x02
#define CMD_AUTHENT 0x03
#define CMD_RECEIVE 0x05
#define CMD_TRANSMIT 0x06
#define CMD_TRANSCEIVE 0x07
#define CMD_WRITEE2 0x08
#define CMD_WRITEE2PAGE 0x09
#define CMD_READE2 0x0A
#define CMD_LOADREG 0x0C
#define CMD_LOADPROTOCOL 0x0D
#define CMD_LOADKEYE2 0x0E
#define CMD_STOREKEYE2 0x0F
#define CMD_CRCCALC 0x1B
#define CMD_READRNR 0x1C
#define CMD_SOFTRESET 0x1F
/** \name Host-Control Register Contents (0x00)
*/
/*@{*/
#define BIT_STANDBY 0x80U /**< Standby bit; If set, the IC transits to standby mode. */
#define BIT_MODEMOFF 0x40U
/*@{*/
/** \name Host-Control Register Contents (0x01)
*/
/*@{*/
#define BIT_I2CFORCEHS 0x01U
//#define BIT_REGEN 0x80U
//#define BIT_BUSHOST 0x40U
//#define BIT_BUSSAM 0x20U
//#define MASK_SAMINTERFACE 0x0CU
/*@}*/
/** \name FIFO-Control Register Contents (0x02)
*/
/*@{*/
#define BIT_FIFOSIZE 0x80U
#define BIT_HIALERT 0x40U
#define BIT_LOALERT 0x20U
#define BIT_FIFOFLUSH 0x10U
#define BIT_WATERLEVEL_HI 0x04U
#define MASK_FIFOLENGTH_HI 0x03U
/*@}*/
/** \name IRQ0 Register(s) Contents (0x06/0x08)
*/
/*@{*/
#define BIT_SET 0x80U
#define BIT_IRQINV 0x80U
#define BIT_HIALERTIRQ 0x40U
#define BIT_LOALERTIRQ 0x20U
#define BIT_IDLEIRQ 0x10U
#define BIT_TXIRQ 0x08U
#define BIT_RXIRQ 0x04U
#define BIT_ERRIRQ 0x02U
#define BIT_RXSOFIRQ 0x01U
/*@}*/
/** \name IRQ1 Register(s) Contents (0x07/0x09)
*/
/*@{*/
/* #define BIT_SET 0x80U */
#define BIT_IRQPUSHPULL 0x80U
#define BIT_GLOBALIRQ 0x40U
#define BIT_IRQPINEN 0x40U
#define BIT_LPCDIRQ 0x20U
#define BIT_TIMER4IRQ 0x10U
#define BIT_TIMER3IRQ 0x08U
#define BIT_TIMER2IRQ 0x04U
#define BIT_TIMER1IRQ 0x02U
#define BIT_TIMER0IRQ 0x01U
/*@}*/
/** \name Error Register Contents (0x0A)
*/
/*@{*/
#define BIT_CMDEE_ERR 0x80U
#define BIT_FIFOWRERR 0x40U
#define BIT_FIFOOVL 0x20U
#define BIT_MINFRAMEERR 0x10U
#define BIT_NODATAERR 0x08U
#define BIT_COLLDET 0x04U
#define BIT_PROTERR 0x02U
#define BIT_INTEGERR 0x01U
/*@}*/
/** \name Status Register Contents (0x0B)
*/
/*@{*/
#define BIT_CRYPTO1ON 0x20U
#define MASK_COMMSTATE 0x07U
/*@}*/
/** \name Rx-Bit-Control Register Contents (0x0C)
*/
/*@{*/
#define BIT_VALUESAFTERCOLL 0x80U
#define BIT_NOCOLL 0x08U
#define MASK_RXALIGN 0x70U
#define MASK_RXLASTBITS 0x07U
/*@}*/
/** \name Rx-Coll Register Contents (0x0D)
*/
/*@{*/
#define BIT_COLLPOSVALID 0x80U
#define MASK_COLLPOS 0x7FU
/*@}*/
/** \name Timer-Control Register Contents (0x0E)
*/
/*@{*/
#define BIT_T3RUNNING 0x80U
#define BIT_T2RUNNING 0x40U
#define BIT_T1RUNNING 0x20U
#define BIT_T0RUNNING 0x10U
#define BIT_T3STARTSTOPNOW 0x08U
#define BIT_T2STARTSTOPNOW 0x04U
#define BIT_T1STARTSTOPNOW 0x02U
#define BIT_T0STARTSTOPNOW 0x01U
/*@}*/
/** \name T[0-3]-Control Register Contents (0x0F/0x14/0x19/0x1E)
*/
/*@{*/
#define BIT_TSTOP_RX 0x80U /**< Stop timer on receive interrupt. */
#define BIT_TAUTORESTARTED 0x08U /**< Auto-restart timer after underflow. */
#define BIT_TSTART_TX 0x10U /**< Start timer on transmit interrupt. */
//#define BIT_TSTART_LFO 0x20U /**< Use this timer for LFO trimming. */
//#define BIT_TSTART_LFO_UV 0x30U /**< Use this timer for LFO trimming (generate UV at a trimming event). */
#define MASK_TSTART 0x30U /**< Mask for TSTART bits. */
#define VALUE_TCLK_1356_MHZ 0x00U /**< Use 13.56MHz as input clock. */
#define VALUE_TCLK_212_KHZ 0x01U /**< Use 212KHz as input clock. */
#define VALUE_TCLK_T0 0x02U /**< Use timer0 as input clock. */
#define VALUE_TCLK_T1 0x03U /**< Use timer1 as input clock. */
/*@}*/
/** \name T4-Control Register Contents (0x23)
*/
/*@{*/
#define BIT_T4RUNNING 0x80U
#define BIT_T4STARTSTOPNOW 0x40U
#define BIT_T4AUTOTRIMM 0x20U
#define BIT_T4AUTOLPCD 0x10U
#define BIT_T4AUTORESTARTED 0x08U
#define BIT_T4AUTOWAKEUP 0x04U
/*#define MASK_TSTART 0x30U*/
#define VALUE_TCLK_LFO_64_KHZ 0x00U
#define VALUE_TCLK_LFO_8_KHZ 0x01U
#define VALUE_TCLK_LFO_4_KHZ 0x02U
#define VALUE_TCLK_LFO_2_KHZ 0x03U
/*@}*/
/** \name Driver Mode Register Contents (0x28)
*/
/*@{*/
#define BIT_TX2INV 0x80U
#define BIT_TX1INV 0x40U
#define BIT_TXEN 0x08U
#define VALUE_TXCLKMODE_HIGHIMPEDANCE 0x00U
#define VALUE_TXCLKMODE_OUTPULL0 0x01U
#define VALUE_TXCLKMODE_OUTPULL1 0x02U
#define VALUE_TXCLKMODE_RFLOWPULL 0x05U
#define VALUE_TXCLKMODE_RFHIGHPUSH 0x06U
#define VALUE_TXCLKMODE_PUSHPULL 0x07U
#define BIT_RFON 0x04U
#define BIT_TPUSHON 0x02U
#define BIT_TPULLON 0x01U
/*@}*/
/** \name Tx Amplifier Register Contents (0x29)
*/
/*@{*/
#define MASK_CW_AMPLITUDE 0x00U
#define MASK_RESIDUAL_CARRIER 0x1FU
/*@}*/
/** \name Driver Control Register Contents (0x2A)
*/
/*@{*/
#define BIT_CWMAX 0x08U
#define BIT_DRIVERINV 0x04U
#define VALUE_DRIVERSEL_LOW 0x00U
#define VALUE_DRIVERSEL_TXENV 0x01U
#define VALUE_DRIVERSEL_SIGIN 0x02U
/*@}*/
/** \name Tx-/Rx-CRC Control Register Contents (0x2C/0x2D)
*/
/*@{*/
#define BIT_RXFORCECRCWRITE 0x80U
#define BIT_CRCINVERT 0x02U
#define BIT_CRCEN 0x01U
#define MASK_CRCPRESETVAL 0x70U
#define MASK_CRCTYPE 0x0CU
#define MASK_CRCTYPE5 0x00U
#define MASK_CRCTYPE16 0x08U
/*@}*/
/** \name Tx-DataNum Register Contents (0x2E)
*/
/*@{*/
#define BIT_KEEPBITGRID 0x10U
#define BIT_DATAEN 0x08U
#define MASK_TXLASTBITS 0x07U
#define MASK_SYMBOL_SEND 0x08U
/*@}*/
/** \name Tx-Wait Control Register Contents (0x31)
*/
/*@{*/
#define BIT_TXWAIT_START_RX 0x80U
#define BIT_TXWAIT_DBFREQ 0x40U
#define MASK_TXWAITHI 0x38U
#define MASK_TXSTOPBITLEN 0x07U
/*@}*/
/** \name Frame Control Register Contents (0x33)
*/
/*@{*/
#define BIT_TXPARITYEN 0x80U
#define BIT_RXPARITYEN 0x40U
#define VALUE_STOP_SYM3 0x0CU
#define VALUE_STOP_SYM2 0x08U
#define VALUE_STOP_SYM1 0x04U
#define VALUE_START_SYM3 0x03U
#define VALUE_START_SYM2 0x02U
#define VALUE_START_SYM1 0x01U
#define MASK_STARTSYM 0x03U
#define MASK_STOPSYM 0x0CU
/*@}*/
/** \name Rx Control Register Contents (0x35)
*/
/*@{*/
#define BIT_RXALLOWBITS 0x80U
#define BIT_RXMULTIPLE 0x40U
#define BIT_RXEOFTYPE 0x20U
#define BIT_EGT_CHECK 0x10U
#define BIT_EMD_SUPPRESSION 0x08U
#define MASK_RXBAUDRATE 0x07U
/*@}*/
/** \name Rx-Wait Register Contents (0x36)
*/
/*@{*/
#define BIT_RXWAITDBFREQ 0x80U
#define MASK_RXWAIT 0x7FU
/*@}*/
/** \name Rx-Threshold Register Contents (0x37)
*/
/*@{*/
#define MASK_MINLEVEL 0xF0U
#define MASK_MINLEVELP 0x0FU
/*@}*/
/** \name Rx-Receiver Register Contents (0x38)
*/
/*@{*/
#define BIT_RX_SINGLE 0x80U
#define BIT_RX_SHORT_MIX2ADC 0x40U
#define BIT_USE_SMALL_EVAL 0x04U
#define MASK_RX_SIGPRO_IN_SEL 0x30U
#define MASK_COLLLEVEL 0x03U
/*@}*/
/** \name Rx-Analog Register Contents (0x39)
*/
/*@{*/
#define BIT_RX_OC_ENABLE 0x20U
#define BIT_RX_HP_LOWF 0x10U
#define MASK_VMID_R_SEL 0xC0U
#define MASK_RCV_HPCF 0x0CU
#define MASK_RCV_GAIN 0x03U
/*@}*/
/** \name Serial-Speed Register Contents (0x3B)
*/
/*@{*/
#define MASK_BR_T0 0xE0U
#define MASK_BR_T1 0x1FU
/*@}*/
/** \name LPCD Result(Q) Register Contents (0x43)
*/
/*@{*/
#define BIT_LPCDIRQ_CLR 0x40U
/*@}*/
/** \name Tx-BitMod Register Contents (0x48)
*/
/*@{*/
#define BIT_TXMSBFIRST 0x80U
#define BIT_TXPARITYTYPE 0x20U
#define BIT_TXSTOPBITTYPE 0x08U
#define BIT_TXSTARTBITTYPE 0x02U
#define BIT_TXSTARTBITEN 0x01U
/*@}*/
/** \name Rx-BitMod Register Contents (0x58)
*/
/*@{*/
#define BIT_RXSTOPONINVPAR 0x20U
#define BIT_RXSTOPONLEN 0x10U
#define BIT_RXMSBFIRST 0x08U
#define BIT_RXSTOPBITEN 0x04U
#define BIT_RXPARITYTYPE 0x02U
/*@}*/
/** \name Rx-Mod Register Contents (0x5D)
*/
/*@{*/
#define BIT_PREFILTER 0x20U
#define BIT_RECTFILTER 0x10U
#define BIT_SYNCHIGH 0x08U
#define BIT_CORRINV 0x04U
#define BIT_FSK 0x02U
#define BIT_BPSK 0x01U
/*@}*/
/** \name RxSupCfg Register Contents (0x6E)
*/
/*@{*/
#define BIT_RXNOERR 0x80U
/*@}*/
/** \name RxTxConReg Register Contents (0x77)
*/
/*@{*/
#define BIT_SHMODE 0x08U //<2F>Ϻ<EFBFBD><CFBA>
/*@}*/
/** \name ErrorExtReg Register Contents (0x7E)
*/
/*@{*/
#define PARITY_ERROR 0x08U
#define CRC_ERROR 0x04U
/*@{*/
#define LPCD_OPTION2 0x1DF
//---------------------------------------------------------------
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Э<EFBFBD><D0AD><EFBFBD><EFBFBD>
#define RX_TYPEA_106 0
#define RX_TYPEA_212 1
#define RX_TYPEA_424 2
#define RX_TYPEA_848 3
#define RX_TYPEB_106 4
#define RX_TYPEB_212 5
#define RX_TYPEB_424 6
#define RX_TYPEB_848 7
#define RX_TYPEV_26 10
#define RX_TYPEV_53 11
#define RX_FELICA_212 19
#define RX_FELICA_424 20
//<2F><><EFBFBD><EFBFBD><E5B7A2>Э<EFBFBD><D0AD><EFBFBD><EFBFBD>
#define TX_TYPEA_106 0
#define TX_TYPEA_212 1
#define TX_TYPEA_424 2
#define TX_TYPEA_848 3
#define TX_TYPEB_106 4
#define TX_TYPEB_212 5
#define TX_TYPEB_424 6
#define TX_TYPEB_848 7
#define TX_TYPEV_26 10
#define TX_TYPEV_53 11
#define TX_FELICA_212 19
#define TX_FELICA_424 20
#endif

View File

@ -0,0 +1,82 @@
/********************************************************************************************************
* @file rfid_main.h
* @brief RFID 读卡器应用层主头文件
* @details
* 本文件定义了RFID应用层所需的数据结构、枚举类型和全局函数。
*
* @author Kilo Code
* @date 2025-11-24
* @version 1.0
********************************************************************************************************/
#ifndef _RFID_MAIN_H
#define _RFID_MAIN_H
// 包含项目的基础类型定义,如果您的项目中没有 "system/includes.h"
// 请替换为包含 stdint.h 或类似的头文件以获取 u8, u16, u32 等类型定义。
#include "system/includes.h"
/**
* @brief 操作状态枚举
*/
typedef enum {
FAIL = 0U,
SUCCESS = !FAIL
} ErrorStatus;
/**
* @brief 功能使能状态枚举
*/
typedef enum {
DISABLE = 0U,
ENABLE = !DISABLE
} FunState;
/**
* @brief 标志位状态枚举
*/
typedef enum {
RESET = 0U,
SET = !RESET
} FlagStatus, ITStatus;
/**
* @brief 通用位宏定义
*/
#define BIT0 (1 << 0)
#define BIT1 (1 << 1)
#define BIT2 (1 << 2)
#define BIT3 (1 << 3)
#define BIT4 (1 << 4)
#define BIT5 (1 << 5)
#define BIT6 (1 << 6)
#define BIT7 (1 << 7)
/**
* @brief 数据传输结构体
* @details 用于在不同函数间传递发送和接收数据缓冲区及其长度信息。
*/
typedef struct
{
unsigned char SendLength; /**< 要发送的数据长度 */
unsigned char *pSendBuffer; /**< 指向发送数据缓冲区的指针 */
unsigned char ReceiveLength; /**< 接收到的数据长度 */
unsigned char *pReceiveBuffer; /**< 指向接收数据缓冲区的指针 */
unsigned int Timeout; /**< 操作超时时间(单位:毫秒) */
} transmission_struct;
/********************************************************************************************************
* 全局函数声明
********************************************************************************************************/
/**
* @brief RFID模块的主任务函数。
* @details
* 这是一个示例性的任务函数展示了如何初始化RFID芯片并进入一个无限循环来轮询不同类型的卡片。
* 您可以将此函数作为一个独立的任务运行,或者将其中的逻辑集成到您现有的任务调度中。
*/
void rfid_task(void);
#endif // _RFID_MAIN_H

View File

@ -0,0 +1,448 @@
#include "../include/READER.h"
#include "../include/CPU_CARD.h"
#include <string.h>
#include "../include/READER_REG.h"
#include "../include/rfid_main.h"
#include "../rfid_hal.h"
#define ENABLE_XLOG 1
#ifdef xlog
#undef xlog
#endif
#if ENABLE_XLOG
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
#else
#define xlog(format, ...) ((void)0)
#endif
struct CPU_CARD_STR CPU_CARD;
// 声明一个静态函数用于TPDU传输因为它只在本文件内部使用
static unsigned char FM176XX_TPDU(transmission_struct *tpdu);
/**
* @brief CPU卡事件处理函数示例
* @details
* 1. 发送RATS (Request for Answer to Select) 命令以激活卡片并获取ATS (Answer to Select)。
* 2. 解析ATS获取卡片能力信息如FSC, FWI等
* 3. 发送一系列APDU (Application Protocol Data Unit) 指令与卡片应用进行交互。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char CPU_CARD_EVENT(void)
{
unsigned char result;
unsigned char SendBuffer[255];
unsigned char ReceiveBuffer[255];
int i;
transmission_struct APDU;
APDU.pSendBuffer = SendBuffer;
APDU.pReceiveBuffer = ReceiveBuffer;
result = CPU_Rats(&CPU_CARD.ATS.Length, CPU_CARD.ATS.Ats_Data);
if (result != SUCCESS)
{
SetCW(DISABLE);
rfid_log_debug("-> RATS ERROR!\r\n");
return result;
}
rfid_log_debug("-> ATS = ");
for(i = 0; i < CPU_CARD.ATS.Length; i++)
rfid_log_debug("%02X", CPU_CARD.ATS.Ats_Data[i]);
rfid_log_debug("\r\n");
result = Ats_Process(CPU_CARD.ATS.Length, CPU_CARD.ATS.Ats_Data);
if (result != SUCCESS)
{
SetCW(DISABLE);
rfid_log_debug("-> ATS Process ERROR!\r\n");
return result;
}
// 选择主文件(MF)
memcpy(APDU.pSendBuffer, "\x00\xA4\x00\x00\x02\x3F\x00", 7);
APDU.SendLength = 7;
result = CPU_APDU(&APDU);
if (result != SUCCESS)
{
SetCW(DISABLE);
rfid_log_debug("-> APDU ERROR!\r\n");
return result;
}
rfid_log_debug("-> Select MF Response = ");
for(i=0; i<APDU.ReceiveLength; i++)
rfid_log_debug("%02X", APDU.pReceiveBuffer[i]);
rfid_log_debug("\r\n");
// ... 此处可以添加更多APDU指令 ...
return result;
}
/**
* @brief 将数据写入芯片的FIFO缓冲区。
* @param length [in] 要写入的数据长度。
* @param buff [in] 指向源数据缓冲区的指针。
* @return 无。
*/
static void Write_FIFO(unsigned char length, unsigned char* buff)
{
unsigned char i;
for(i=0; i<length; i++)
{
SetReg(REG_FIFODATA,buff[i]);
}
}
/**
* @brief 从芯片的FIFO缓冲区读取数据。
* @param length [in] 要读取的数据长度。
* @param buff [out] 指向目标数据缓冲区的指针。
* @return 无。
*/
static void Read_FIFO(unsigned char length, unsigned char* buff)
{
unsigned char i;
for(i=0; i<length; i++)
{
GetReg(REG_FIFODATA,&buff[i]);
}
}
/**
* @brief 执行TPDU (Transmission Protocol Data Unit) 数据交换。
* @param tpdu [in, out] 指向 `transmission_struct` 结构体的指针,包含发送和接收信息。
* @return 操作状态SUCCESS表示成功FAIL表示超时或出错。
* @details
* 这是与卡片进行底层数据块交换的核心函数。它负责:
* - 将数据写入FIFO。
* - 启动TRANSCEIVE命令。
* - 等待接收中断或超时。
* - 从FIFO读取响应数据。
* - 检查错误状态。
*/
static unsigned char FM176XX_TPDU(transmission_struct *tpdu)
{
unsigned char irq0, error;
unsigned int i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM,0x08);
SetReg(REG_IRQ0,0x7F); // 清除IRQ0所有中断标志
SetReg(REG_IRQ1,0x7F); // 清除IRQ1所有中断标志
ModifyReg(REG_FIFOCONTROL,BIT_FIFOFLUSH,ENABLE); // 清空FIFO
Write_FIFO(tpdu->SendLength,tpdu->pSendBuffer);
ModifyReg(REG_TXCRCCON, BIT_CRCEN,ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN,ENABLE);
// SetTimer(tpdu->Timeout); // 定时器功能可以根据需要启用
SetCommand(CMD_TRANSCEIVE);
// 等待接收完成或超时
for(i = 0; i < tpdu->Timeout; i++)
{
rfid_delay_ms(1);
GetReg(REG_IRQ0,&irq0);
if(irq0 & BIT_RXIRQ) // 检查是否收到数据
{
GetReg(REG_ERROR, &error); // 获取错误状态
error &= (BIT_NODATAERR | BIT_COLLDET | BIT_PROTERR | BIT_INTEGERR);
if(error != 0)
return FAIL; // 接收到错误
GetReg(REG_FIFOLENGTH, &tpdu->ReceiveLength);
if(tpdu->ReceiveLength > 0)
{
Read_FIFO(tpdu->ReceiveLength,tpdu->pReceiveBuffer);
return SUCCESS;
}
}
}
return FAIL; // 超时
}
/**
* @brief 发送RATS (Request for Answer to Select) 命令。
* @param ats_len [out] 指向用于存储ATS长度的变量的指针。
* @param ats [out] 指向用于存储ATS数据的缓冲区的指针。
* @return 操作状态SUCCESS表示成功。
* @details
* RATS是激活ISO/IEC 14443-4卡片的第一步用于获取卡片的基本通信参数。
*/
unsigned char CPU_Rats(unsigned char *ats_len, unsigned char *ats)
{
unsigned char result;
unsigned char outbuffer[2], inbuffer[64];
transmission_struct tpdu;
tpdu.pSendBuffer = outbuffer;
tpdu.pReceiveBuffer = inbuffer;
tpdu.pSendBuffer[0] = 0xE0; // RATS命令起始字节
tpdu.pSendBuffer[1] = 0x50; // 参数字节 (FSDI=5, CID=0)
tpdu.SendLength = 2;
tpdu.Timeout = 160; // 超时时间
result = FM176XX_TPDU(&tpdu);
if (result == SUCCESS)
{
*ats_len = tpdu.ReceiveLength;
memcpy(ats, tpdu.pReceiveBuffer, *ats_len);
}
return (result);
}
/**
* @brief 解析ATS (Answer to Select) 数据。
* @param ats_len [in] ATS数据的长度。
* @param ats [in] 指向ATS数据的指针。
* @return 操作状态SUCCESS表示成功。
* @details
* 此函数从ATS响应中提取关键参数如FSC (Frame Size for proximity coupling)、
* FWI (Frame Waiting time Integer)等,并存储在全局的 `CPU_CARD` 结构体中。
*/
unsigned char Ats_Process(unsigned char ats_len, unsigned char *ats)
{
unsigned char offset;
if (ats_len < 2) return FAIL;
// 解析FSCI (Frame Size for proximity coupling Integer) -> FSC
CPU_CARD.FSCI = ats[1] & 0x0F;
switch(CPU_CARD.FSCI) {
case 0: CPU_CARD.FSC = 16; break;
case 1: CPU_CARD.FSC = 24; break;
case 2: CPU_CARD.FSC = 32; break;
case 3: CPU_CARD.FSC = 40; break;
case 4: CPU_CARD.FSC = 48; break;
case 5: CPU_CARD.FSC = 64; break;
case 6: CPU_CARD.FSC = 96; break;
case 7: CPU_CARD.FSC = 128; break;
case 8: CPU_CARD.FSC = 256; break;
default: CPU_CARD.FSC = 32; break; // 默认值
}
xlog("-> CPU_CARD.FSC = %d\r\n", CPU_CARD.FSC);
offset = 0;
if (ats[1] & BIT4) // TA(1) present
{
CPU_CARD.TA = ats[2];
offset++;
}
if (ats[1] & BIT5) // TB(1) present
{
CPU_CARD.TB = ats[2 + offset];
CPU_CARD.SFGI = CPU_CARD.TB & 0x0F;
CPU_CARD.FWI = (CPU_CARD.TB >> 4) & 0x0F;
xlog("-> CPU_CARD.SFGI = %02X\r\n", CPU_CARD.SFGI);
xlog("-> CPU_CARD.FWI = %02X\r\n", CPU_CARD.FWI);
// 根据FWI计算FWT (Frame Waiting Time)
unsigned long base_fwt = 256 * 16 / 13560; // (256 * 16 / fc) in ms
CPU_CARD.FWT = base_fwt * (1 << CPU_CARD.FWI);
offset++;
} else {
CPU_CARD.FWT = 160; // 默认FWT
}
if (ats[1] & BIT6) // TC(1) present
{
CPU_CARD.TC = ats[2 + offset];
offset++;
}
CPU_CARD.PCB = 0x02; // PCB初始值为0x02
return SUCCESS;
}
/**
* @brief 发送NAK (Negative Acknowledge) 响应。
* @param tpdu [in, out] 指向传输结构体的指针。
* @return 操作状态。
* @details
* 在TPDU交换中如果接收到错误的数据块会发送NAK请求重发。
*/
unsigned char CPU_NAK(transmission_struct *tpdu)
{
unsigned char result, tpdu_send_buffer[1], tpdu_receive_buffer[255];
tpdu->pSendBuffer = tpdu_send_buffer;
tpdu->pReceiveBuffer = tpdu_receive_buffer;
tpdu->pSendBuffer[0] = 0xB0 | CPU_CARD.PCB; // NAK PCB
tpdu->SendLength = 1;
result = FM176XX_TPDU(tpdu);
return (result);
}
/**
* @brief 封装了重试逻辑的TPDU传输函数。
* @param tpdu [in, out] 指向传输结构体的指针。
* @return 操作状态。
* @details
* 此函数调用底层的 `FM176XX_TPDU`并在失败时进行最多3次重试。
* 它还处理ACK/NAK逻辑以确保数据的可靠传输。
*/
unsigned char CPU_TPDU(transmission_struct *tpdu)
{
unsigned char result, i, pcb_byte;
transmission_struct nak_tpdu;
result = FM176XX_TPDU(tpdu);
for (i = 0; i < 3; i++)
{
if (result != SUCCESS)
{
result = CPU_NAK(&nak_tpdu);
if(result == SUCCESS && nak_tpdu.ReceiveLength > 0)
{
memcpy(&pcb_byte, nak_tpdu.pReceiveBuffer, 1);
if((pcb_byte & 0xF0) == 0xA0) // R(ACK)
{
xlog("...pcb_byte = %02X\r\n", pcb_byte);
xlog("...CPU_CARD.PCB = %02X\r\n", CPU_CARD.PCB);
if((pcb_byte & 0x01) != (CPU_CARD.PCB & 0x01))
{
result = FM176XX_TPDU(tpdu);
}
else
{
tpdu->pSendBuffer[0] ^= 0x01; // 翻转序列号位
CPU_CARD.PCB = tpdu->pSendBuffer[0] & 0x01;
result = FM176XX_TPDU(tpdu);
}
}
}
}
else
{
break; // 成功则退出循环
}
}
return (result);
}
/**
* @brief 发送APDU (Application Protocol Data Unit) 命令。
* @param apdu [in, out] 指向传输结构体的指针包含APDU命令和响应。
* @return 操作状态。
* @details
* 此函数处理APDU的块链接chaining逻辑。如果APDU长度超过卡片的最大帧大小FSC
* 它会自动将APDU分割成多个TPDU块进行传输。
*/
unsigned char CPU_APDU(transmission_struct *apdu)
{
unsigned char result, pcb_byte, i;
unsigned char tpdu_send_buffer[256], tpdu_receive_buffer[256];
unsigned int unsent_length;
transmission_struct tpdu;
tpdu.pSendBuffer = tpdu_send_buffer;
tpdu.pReceiveBuffer = tpdu_receive_buffer;
tpdu.Timeout = CPU_CARD.FWT;
apdu->ReceiveLength = 0;
unsent_length = apdu->SendLength;
// --- 发送阶段 ---
for (i = 0; i < 16; i++) // 最多16个链式块
{
xlog("unsent_length = %d\r\n", unsent_length);
if (unsent_length <= (CPU_CARD.FSC - 1))
{
// 最后一个或唯一的数据块
tpdu.pSendBuffer[0] = CPU_CARD.PCB; // I-Block, no chaining
memcpy(tpdu.pSendBuffer + 1, apdu->pSendBuffer + apdu->SendLength - unsent_length, unsent_length);
tpdu.SendLength = unsent_length + 1;
xlog("--> ");
for(int j=0; j<tpdu.SendLength; j++) xlog("%02X", tpdu.pSendBuffer[j]);
xlog("\r\n");
result = CPU_TPDU(&tpdu);
if ((result != SUCCESS) || (tpdu.ReceiveLength == 0))
return (result);
xlog("<-- ");
for(int j=0; j<tpdu.ReceiveLength; j++) xlog("%02X", tpdu.pReceiveBuffer[j]);
xlog("\r\n");
unsent_length = 0;
break; // 发送完成
}
else
{
// 需要分块传输
tpdu.pSendBuffer[0] = CPU_CARD.PCB | 0x10; // I-Block with chaining
memcpy(tpdu.pSendBuffer + 1, apdu->pSendBuffer + apdu->SendLength - unsent_length, CPU_CARD.FSC - 1);
tpdu.SendLength = CPU_CARD.FSC;
xlog("..--> ");
for(int j=0; j<tpdu.SendLength; j++) xlog("%02X", tpdu.pSendBuffer[j]);
xlog("\r\n");
result = CPU_TPDU(&tpdu);
xlog("<-- ");
for(int j=0; j<tpdu.ReceiveLength; j++) xlog("%02X", tpdu.pReceiveBuffer[j]);
xlog("\r\n");
if ((result != SUCCESS) || (tpdu.ReceiveLength != 1))
return (result);
memcpy(&pcb_byte, tpdu.pReceiveBuffer, 1);
if ((pcb_byte & 0xE0) == 0xA0) // R(ACK) block
{
unsent_length -= (CPU_CARD.FSC - 1);
CPU_CARD.PCB = (pcb_byte & 0x01) ^ 0x01; // 更新序列号
xlog("unsent_length = %d\r\n", unsent_length);
}
else
{
return (FAIL); // 未收到预期的ACK
}
}
}
// --- 接收阶段 ---
for (i = 0; i < 255; i++) // 最多255个链式块
{
if ((result != SUCCESS) || (tpdu.ReceiveLength == 0))
return (FAIL);
memcpy(&pcb_byte, tpdu.pReceiveBuffer, 1);
if ((pcb_byte & 0xC0) == 0x00) // I-Block
{
CPU_CARD.PCB = (pcb_byte & 0x01) ^ 0x01;
memcpy(apdu->pReceiveBuffer + apdu->ReceiveLength, tpdu.pReceiveBuffer + 1, tpdu.ReceiveLength - 1);
apdu->ReceiveLength += (tpdu.ReceiveLength - 1);
if (pcb_byte & 0x10) // 还有后续数据块
{
tpdu.pSendBuffer[0] = 0xA0 | CPU_CARD.PCB; // 发送ACK
tpdu.SendLength = 1;
xlog("...--> ACK = %02X\r\n", tpdu.pSendBuffer[0]);
result = CPU_TPDU(&tpdu);
}
else // 最后一个数据块
{
return SUCCESS;
}
}
else if ((pcb_byte & 0xE0) == 0xE0) // S-Block (WTX)
{
// 回复WTX响应
memcpy(tpdu.pSendBuffer, tpdu.pReceiveBuffer, tpdu.ReceiveLength);
tpdu.SendLength = tpdu.ReceiveLength;
xlog("....--> WTX = ");
for(int j=0; j<tpdu.SendLength; j++) xlog("%02X", tpdu.pSendBuffer[j]);
xlog("\r\n");
result = CPU_TPDU(&tpdu);
}
else
{
return FAIL; // 未知响应
}
}
return (FAIL); // 接收块过多
}

View File

@ -0,0 +1,456 @@
#include "../include/MIFARE.h"
#include "../include/READER.h"
#include "string.h"
#include "../include/READER_REG.h"
#include "../include/rfid_main.h"
#include "../rfid_hal.h"
#define ENABLE_XLOG 1
#ifdef xlog
#undef xlog
#endif
#if ENABLE_XLOG
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
#else
#define xlog(format, ...) ((void)0)
#endif
unsigned char SECTOR,BLOCK,BLOCK_NUM;
unsigned char BLOCK_DATA[16];
unsigned char KEY_A[16][6]=
{{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//0
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//1
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//2
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//3
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//4
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//5
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//6
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//7
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//8
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//9
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//10
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//11
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//12
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//13
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//14
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};//15
unsigned char KEY_B[16][6]=
{{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//0
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//1
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//2
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//3
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//4
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//5
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//6
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//7
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//8
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//9
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//10
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//11
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//12
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//13
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},//14
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};//15
/**
* @brief 清除Mifare卡加密认证标志。
* @details
* 在对Mifare卡进行认证Authentication芯片内部会设置一个加密标志位BIT_CRYPTO1ON
* 此函数用于清除该标志,以便可以对新的扇区进行认证或执行非加密操作。
* @return 无。
*/
void Mifare_Clear_Crypto(void)
{
ModifyReg(REG_STATUS,BIT_CRYPTO1ON,RESET);
return;
}
/**
* @brief Mifare卡事件处理函数示例
* @details
* 这是一个示例函数演示了对Mifare Classic卡进行读写操作的完整流程
* 1. 清除加密状态。
* 2. 对指定的扇区例如扇区1使用密钥A进行认证。
* 3. 如果认证成功则遍历该扇区的数据块块0到块2
* 4. 对每个块先执行写操作写入16字节的0xFF。
* 5. 然后再执行读操作,将数据读回并打印。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char MIFARE_CARD_EVENT(void)
{
unsigned char result;
int i;
Mifare_Clear_Crypto();
SECTOR = 1;
//for(SECTOR = 0;SECTOR < 16; SECTOR++)
{
BLOCK_NUM = (SECTOR * 4) + BLOCK;
result = Mifare_Auth(KEY_A_M1,SECTOR,KEY_A[SECTOR],PICC_A.UID);
if(result != SUCCESS)
{
SetCW(DISABLE);
xlog("-> AUTH ERROR!\r\n");
return result;
}
xlog("-> AUTH SUCCESS!\r\n");
for(BLOCK = 0;BLOCK < 3;BLOCK++)
{
BLOCK_NUM = (SECTOR * 4) + BLOCK;
if(BLOCK_NUM == 0)
BLOCK_NUM = 1;
xlog("-> SECTOR = %02X\r\n",SECTOR);;
xlog("-> BLOCK = %02X\r\n",BLOCK);
xlog("-> BLOCK_NUM = %02X\r\n",BLOCK_NUM);
memcpy(BLOCK_DATA,"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",16);
result = Mifare_Blockwrite(BLOCK_NUM,BLOCK_DATA);
if(result != SUCCESS)
{
SetCW(DISABLE);
xlog("-> WRITE BLOCK ERROR!\r\n");
return result;
}
xlog("-> WRITE BLOCK SUCCESS!\r\n");
result = Mifare_Blockread(BLOCK_NUM,BLOCK_DATA);
if(result != SUCCESS)
{
SetCW(DISABLE);
xlog("-> READ BLOCK ERROR!\r\n");
return result;
}
xlog("-> READ BLOCK = ");
for(i=0; i<16; i++) xlog("%02X", BLOCK_DATA[i]);
xlog("\r\n");
}
}
SetCW(DISABLE);
return result;
}
/**
* @brief 将6字节的Mifare密钥加载到芯片的密钥缓冲区。
* @param mifare_key [in] 指向6字节密钥数组的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
* @details
* 在执行认证命令Mifare_Auth之前必须先调用此函数将要使用的密钥加载到芯片内部。
*/
unsigned char Mifare_LoadKey(unsigned char *mifare_key)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
ModifyReg(REG_FIFOCONTROL,BIT_FIFOFLUSH,ENABLE); //Clear FIFO
SetReg(REG_FIFODATA,mifare_key[0]);
SetReg(REG_FIFODATA,mifare_key[1]);
SetReg(REG_FIFODATA,mifare_key[2]);
SetReg(REG_FIFODATA,mifare_key[3]);
SetReg(REG_FIFODATA,mifare_key[4]);
SetReg(REG_FIFODATA,mifare_key[5]);
SetCommand(CMD_LOADKEY);
rfid_delay_ms(1);
GetReg(REG_COMMAND,&reg_data);
if((reg_data & CMD_MASK) == CMD_IDLE)
return SUCCESS;
else
return FAIL;
}
/**
* @brief 对Mifare Classic卡片的指定扇区进行认证。
* @param key_mode [in] 认证模式,`KEY_A_M1` (0) 表示使用密钥A`KEY_B_M1` (1) 表示使用密钥B。
* @param sector [in] 要认证的扇区号 (0-15)。
* @param mifare_key [in] 指向6字节认证密钥的指针。
* @param card_uid [in] 指向4字节卡片UID的指针。
* @return 操作状态SUCCESS表示认证成功FAIL表示失败。
* @details
* 这是访问Mifare卡数据块之前的必要步骤。认证成功后芯片会设置加密标志位。
*/
unsigned char Mifare_Auth(unsigned char key_mode,unsigned char sector,unsigned char *mifare_key,unsigned char *card_uid)
{
unsigned char result,reg_data;
result = Mifare_LoadKey(mifare_key);
if (result != SUCCESS)
return result;
SetCommand(CMD_IDLE);
ModifyReg(REG_FIFOCONTROL,BIT_FIFOFLUSH,ENABLE); //Clear FIFO
if(key_mode == KEY_A_M1)
{
SetReg(REG_FIFODATA,0x60);// 0x60: Key A认证指令
ModifyReg(REG_RXTXCON,BIT_SHMODE,DISABLE);
}
if(key_mode == KEY_B_M1)
{
SetReg(REG_FIFODATA,0x61);// 0x61: Key B认证指令
ModifyReg(REG_RXTXCON,BIT_SHMODE,DISABLE);
}
SetReg(REG_FIFODATA,sector * 4);// 认证扇区的块0地址
SetReg(REG_FIFODATA,card_uid[0]);
SetReg(REG_FIFODATA,card_uid[1]);
SetReg(REG_FIFODATA,card_uid[2]);
SetReg(REG_FIFODATA,card_uid[3]);
ModifyReg(REG_TXCRCCON, BIT_CRCEN,ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN,ENABLE);
SetCommand(CMD_AUTHENT);
rfid_delay_ms(5);
GetReg(REG_COMMAND,&reg_data);
if((reg_data & CMD_MASK) == CMD_IDLE)
{
GetReg(REG_STATUS,&reg_data);
if(reg_data & BIT_CRYPTO1ON)// 检查加密标志位以确认认证成功
return SUCCESS;
}
return FAIL;
}
/**
* @brief 将4字节数据格式化为Mifare值块格式并写入指定块。
* @param block [in] 目标块号。
* @param data_buff [in] 指向4字节源数据的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
* @details
* Mifare值块有特定的数据格式包含值、值的反码和地址字节。此函数会自动处理格式转换。
*/
unsigned char Mifare_Blockset(unsigned char block,unsigned char *data_buff)
{
unsigned char block_data[16],result;
// 格式化为值块
block_data[0] = data_buff[3];
block_data[1] = data_buff[2];
block_data[2] = data_buff[1];
block_data[3] = data_buff[0];
block_data[4] = ~data_buff[3];
block_data[5] = ~data_buff[2];
block_data[6] = ~data_buff[1];
block_data[7] = ~data_buff[0];
block_data[8] = data_buff[3];
block_data[9] = data_buff[2];
block_data[10] = data_buff[1];
block_data[11] = data_buff[0];
block_data[12] = block;
block_data[13] = ~block;
block_data[14] = block;
block_data[15] = ~block;
result = Mifare_Blockwrite(block,block_data);
return result;
}
/**
* @brief 从Mifare卡读取一个16字节的数据块。
* @param block [in] 要读取的块号 (0x00 - 0x3F)。
* @param data_buff [out] 指向16字节缓冲区的指针用于存储读取的数据。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char Mifare_Blockread(unsigned char block,unsigned char *data_buff)
{
unsigned char reg_data,i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM,0x08);
SetReg(REG_FIFODATA,0x30);// 0x30: 读块指令
SetReg(REG_FIFODATA,block);// 块地址
ModifyReg(REG_TXCRCCON, BIT_CRCEN,ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN,ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(2);
GetReg(REG_FIFOLENGTH,&reg_data);
if (reg_data != 16) // 成功时应返回16字节数据
return FAIL;
GetReg(REG_ERROR,&reg_data);
if(reg_data & 0x07)
return FAIL;
for(i=0;i<16;i++)
{
GetReg (REG_FIFODATA,&data_buff[i]);
}
return SUCCESS;
}
/**
* @brief 向Mifare卡写入一个16字节的数据块。
* @param block [in] 要写入的块号 (0x00 - 0x3F)。
* @param data_buff [in] 指向16字节数据的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char Mifare_Blockwrite(unsigned char block,unsigned char *data_buff)
{
unsigned char reg_data,i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM,0x08);
SetReg(REG_FIFODATA,0xA0);// 0xA0: 写块指令
SetReg(REG_FIFODATA,block);// 块地址
ModifyReg(REG_TXCRCCON, BIT_CRCEN,ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN,DISABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_FIFOLENGTH,&reg_data);
if (reg_data != 1) // 接收到ACK (0x0A)
return FAIL;
GetReg (REG_FIFODATA,&reg_data);
if(reg_data != 0x0A)
return FAIL;
for(i=0;i<16;i++)
{
SetReg(REG_FIFODATA,data_buff[i]);
}
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_FIFOLENGTH,&reg_data);
if (reg_data != 1) // 接收到ACK (0x0A)
return FAIL;
GetReg (REG_FIFODATA,&reg_data);
if(reg_data != 0x0A)
return FAIL;
return SUCCESS;
}
/**
* @brief 对Mifare卡的指定值块执行增值操作。
* @param block [in] 值块的块号。
* @param data_buff [in] 指向4字节增值数据的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char Mifare_Blockinc(unsigned char block,unsigned char *data_buff)
{
unsigned char reg_data,i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM,0x08);
SetReg(REG_FIFODATA,0xC1);// 0xC1: 增值指令
SetReg(REG_FIFODATA,block);// 块地址
ModifyReg(REG_TXCRCCON, BIT_CRCEN,ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN,DISABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_FIFOLENGTH,&reg_data);
if (reg_data != 1)
return FAIL;
GetReg (REG_FIFODATA,&reg_data);
if(reg_data != 0x0A)
return FAIL;
for(i=0;i<4;i++)
{
SetReg(REG_FIFODATA,data_buff[i]);
}
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_FIFOLENGTH,&reg_data);
if (reg_data != 1)
return FAIL;
GetReg (REG_FIFODATA,&reg_data);
if(reg_data != 0x0A)
return FAIL;
return SUCCESS;
}
/**
* @brief 对Mifare卡的指定值块执行减值操作。
* @param block [in] 值块的块号。
* @param data_buff [in] 指向4字节减值数据的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char Mifare_Blockdec(unsigned char block,unsigned char *data_buff)
{
unsigned char reg_data,i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM,0x08);
SetReg(REG_FIFODATA,0xC0);// 0xC0: 减值指令
SetReg(REG_FIFODATA,block);// 块地址
ModifyReg(REG_TXCRCCON, BIT_CRCEN,ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN,DISABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_FIFOLENGTH,&reg_data);
if (reg_data != 1)
return FAIL;
GetReg (REG_FIFODATA,&reg_data);
if(reg_data != 0x0A)
return FAIL;
for(i=0;i<4;i++)
{
SetReg(REG_FIFODATA,data_buff[i]);
}
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_FIFOLENGTH,&reg_data);
if (reg_data != 1)
return FAIL;
GetReg (REG_FIFODATA,&reg_data);
if(reg_data != 0x0A)
return FAIL;
return SUCCESS;
}
/**
* @brief 执行Mifare卡的传输Transfer命令。
* @param block [in] 块号。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
* @details
* 在对值块进行增/减值操作后,需要调用此函数将结果从内部寄存器写入到块中。
*/
unsigned char Mifare_Transfer(unsigned char block)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM,0x08);
SetReg(REG_FIFODATA,0xB0);// 0xB0: Transfer指令
SetReg(REG_FIFODATA,block);// 块地址
ModifyReg(REG_TXCRCCON, BIT_CRCEN,ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN,DISABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_FIFOLENGTH,&reg_data);
if (reg_data != 1)
return FAIL;
GetReg (REG_FIFODATA,&reg_data);
if(reg_data != 0x0A)
return FAIL;
return SUCCESS;
}
/**
* @brief 执行Mifare卡的恢复Restore命令。
* @param block [in] 块号。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
* @details
* 此命令用于将一个块的内容从内部寄存器中恢复。
*/
unsigned char Mifare_Restore(unsigned char block)
{
unsigned char reg_data,i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM,0x08);
SetReg(REG_FIFODATA,0xC2);// 0xC2: Restore指令
SetReg(REG_FIFODATA,block);// 块地址
ModifyReg(REG_TXCRCCON, BIT_CRCEN,ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN,DISABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_FIFOLENGTH,&reg_data);
if (reg_data != 1)
return FAIL;
GetReg (REG_FIFODATA,&reg_data);
if(reg_data != 0x0A)
return FAIL;
for(i=0;i<4;i++)
{
SetReg(REG_FIFODATA,0);
}
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_FIFOLENGTH,&reg_data);
if (reg_data != 1)
return FAIL;
GetReg (REG_FIFODATA,&reg_data);
if(reg_data != 0x0A)
return FAIL;
return SUCCESS;
}

View File

@ -0,0 +1,109 @@
#include "../include/READER.h"
#include "../include/NTAG.h"
#include <string.h>
#include "../include/READER_REG.h"
#include "../include/rfid_main.h"
#include "../rfid_hal.h"
#define ENABLE_XLOG 1
#ifdef xlog
#undef xlog
#endif
#if ENABLE_XLOG
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
#else
#define xlog(format, ...) ((void)0)
#endif
unsigned char PAGE_DATA[16];
/**
* @brief NTAG卡事件处理函数示例
* @details
* 这是一个示例函数演示了对NTAG系列卡片进行读写操作的流程
* 1. 准备要写入的数据4字节
* 2. 调用 `Write_Page()` 函数将数据写入第8页。
* 3. 调用 `Read_Page()` 函数从第8页读回数据并打印以进行验证。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char NTAG_EVENT(void)
{
unsigned char result;
memcpy(PAGE_DATA,"\x01\x02\x03\x04",4);
result = Write_Page(8,PAGE_DATA);
if (result != SUCCESS)
return result;
xlog("PAGE 8 Write OK\r\n");
result = Read_Page(8,PAGE_DATA);
xlog("PAGE 8 = %02X%02X%02X%02X\r\n",PAGE_DATA[0],PAGE_DATA[1],PAGE_DATA[2],PAGE_DATA[3]);
return result;
}
/**
* @brief 从NTAG卡读取一个或多个页的数据。
* @param page_num [in] 要读取的起始页号。
* @param page_data [out] 指向缓冲区的指针用于存储读取的数据。对于NTAG21x系列一次最少读取16字节4页
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char Read_Page(unsigned char page_num,unsigned char *page_data)
{
unsigned char reg_data,i;
SetCommand(CMD_IDLE);
Clear_FIFO();
SetReg(REG_FIFODATA,0x30); // 读指令
SetReg(REG_FIFODATA,page_num);
ModifyReg(REG_TXCRCCON, BIT_CRCEN,ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN,ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_ERROR,&reg_data);
if(reg_data & 0x07)
return FAIL;
GetReg(REG_FIFOLENGTH,&reg_data);
if(reg_data != 16) // NTAG一次读取返回16字节
return FAIL;
for(i=0;i<16;i++)
{
GetReg(REG_FIFODATA,&page_data[i]);
}
return SUCCESS;
}
/**
* @brief 向NTAG卡的一个页Page写入4字节数据。
* @param page_num [in] 要写入的页号。
* @param page_data [in] 指向4字节数据的指针。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char Write_Page(unsigned char page_num,unsigned char *page_data)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
Clear_FIFO();
SetReg(REG_FIFODATA,0xA2); // 写指令
SetReg(REG_FIFODATA,page_num);
SetReg(REG_FIFODATA,page_data[0]);
SetReg(REG_FIFODATA,page_data[1]);
SetReg(REG_FIFODATA,page_data[2]);
SetReg(REG_FIFODATA,page_data[3]);
ModifyReg(REG_TXCRCCON, BIT_CRCEN,ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN,DISABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(5);
GetReg(REG_FIFOLENGTH,&reg_data);
if(reg_data != 1) // 应该收到一个ACK
return FAIL;
GetReg(REG_FIFODATA,&reg_data);
if(reg_data != 0x0A) // ACK的值为0x0A
return FAIL;
return SUCCESS;
}

View File

@ -0,0 +1,774 @@
/********************************************************************************************************
* @file READER.c
* @brief RFID 读卡器底层驱动及协议实现
* @details
* 本文件实现了与FM176XX系列RFID芯片的底层通信协议。它包含以下功能
* - 控制芯片进入不同工作模式如Type A, B, V, F
* - 实现各种卡片类型的寻卡、防冲突、选择和数据交换命令。
* - 管理芯片的FIFO、定时器和RF场。
* 所有硬件相关的操作均通过 `rfid_hal.h` 中定义的接口完成。
********************************************************************************************************/
#include "../include/READER.h"
#include "../include/READER_REG.h"
#include "../include/rfid_main.h"
#include "../rfid_hal.h" // 引入硬件抽象层
#include <string.h>
#define ENABLE_XLOG 1
#ifdef xlog
#undef xlog
#endif
#if ENABLE_XLOG
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
#else
#define xlog(format, ...) ((void)0)
#endif
// 定义全局变量以存储不同类型卡片的信息
struct picc_a_struct PICC_A;
struct picc_b_struct PICC_B;
struct picc_v_struct PICC_V;
struct picc_f_struct PICC_F;
/********************************************************************************************************
* 公共接口函数
********************************************************************************************************/
/**
* @brief 修改寄存器的特定位。
* @param reg_address [in] 目标寄存器的地址。
* @param mask [in] 要修改的位的掩码。
* @param set [in] 如果为非0则将掩码对应的位设置为1如果为0则清零。
* @return 无。
* @details
* 这是一个“读-改-写”操作。首先读取寄存器的当前值,然后根据掩码和`set`参数修改它,
* 最后将修改后的值写回寄存器。
*/
void ModifyReg(unsigned char reg_address, unsigned char mask, unsigned char set)
{
unsigned char reg_data;
GetReg(reg_address, &reg_data);
if (set)
{
reg_data |= mask;
}
else
{
reg_data &= ~mask;
}
SetReg(reg_address, reg_data);
}
/**
* @brief 向命令寄存器写入一个命令。
* @param command [in] 要执行的命令代码如CMD_IDLE, CMD_TRANSCEIVE等
* @return 操作状态SUCCESS表示成功。
*/
unsigned char SetCommand(unsigned char command)
{
return SetReg(REG_COMMAND, CMD_MASK & command);
}
/**
* @brief 设置芯片内部定时器的超时时间。
* @param timeout [in] 超时时间,单位为毫秒(ms)。
* @return 无。
* @details
* 根据输入的超时时间计算合适的预分频值和重载值并配置T0和T1定时器。
* 这用于在收发数据时进行超时检测。
*/
void SetTimer(unsigned int timeout)
{
unsigned long prescale = 1;
unsigned long t, fc;
fc = timeout * 13560; // 13.56MHz时钟频率
t = fc;
while (fc > 65535)
{
prescale *= 2;
fc = t / prescale;
if (fc * prescale != t)
fc++;
}
if (prescale > 1)
{
SetReg(REG_T0CONTROL, BIT_TSTOP_RX | BIT_TSTART_TX | BIT_TAUTORESTARTED | VALUE_TCLK_1356_MHZ);
SetReg(REG_T0RELOADHI, (unsigned char)(fc >> 8));
SetReg(REG_T0RELOADLO, (unsigned char)fc);
SetReg(REG_T1CONTROL, BIT_TSTOP_RX | BIT_TSTART_TX | VALUE_TCLK_T0);
SetReg(REG_T1RELOADHI, (unsigned char)(prescale >> 8));
SetReg(REG_T1RELOADLO, (unsigned char)prescale);
}
else
{
SetReg(REG_T1CONTROL, BIT_TSTOP_RX | BIT_TSTART_TX | VALUE_TCLK_1356_MHZ);
SetReg(REG_T1RELOADHI, (unsigned char)(fc >> 8));
SetReg(REG_T1RELOADLO, (unsigned char)fc);
}
}
/**
* @brief 打开或关闭RF场载波
* @param mode [in] ENABLE表示打开DISABLE表示关闭。
* @return 操作状态SUCCESS表示成功。
*/
unsigned char SetCW(unsigned char mode)
{
if (mode == ENABLE)
{
ModifyReg(REG_COMMAND, BIT_MODEMOFF, DISABLE);
ModifyReg(REG_TXMODE, BIT_TPUSHON | BIT_TPULLON, ENABLE);
}
else
{
ModifyReg(REG_COMMAND, BIT_MODEMOFF, ENABLE);
ModifyReg(REG_TXMODE, BIT_TPUSHON | BIT_TPULLON, DISABLE);
}
rfid_delay_ms(5);
return SUCCESS;
}
/**
* @brief 清空芯片内部的FIFO缓冲区。
* @return 无。
*/
void Clear_FIFO(void)
{
unsigned char fifolength;
GetReg(REG_FIFOLENGTH, &fifolength);
if (fifolength != 0)
{
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
}
}
/**
* @brief 加载指定的通信协议参数到芯片。
* @param p_rx [in] 接收协议代码。
* @param p_tx [in] 发送协议代码。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
* @details
* 不同的卡片类型A, B, V, F使用不同的通信速率和编码方式
* 此函数用于将这些协议参数加载到芯片中。
*/
unsigned char LoadProtocol(unsigned char p_rx, unsigned char p_tx)
{
unsigned char reg_data = 0;
SetCommand(CMD_IDLE);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE); // 清空FIFO
SetReg(REG_FIFODATA, p_rx); // 写入接收协议
SetReg(REG_FIFODATA, p_tx); // 写入发送协议
SetCommand(CMD_LOADPROTOCOL);
rfid_delay_ms(2);
GetReg(REG_COMMAND, &reg_data);
if (reg_data != CMD_IDLE)
return FAIL;
return SUCCESS;
}
/**
* @brief 设置发送和接收的奇偶校验位使能状态。
* @param state [in] ENABLE或DISABLE。
* @return 无。
*/
void SetParity(unsigned char state)
{
ModifyReg(REG_FRAMECON, BIT_TXPARITYEN | BIT_RXPARITYEN, state);
}
/**
* @brief 初始化读卡器以支持Type A卡片。
* @return 操作状态SUCCESS表示成功。
*/
unsigned char ReaderA_Initial(void)
{
LoadProtocol(RX_TYPEA_106, TX_TYPEA_106);
ModifyReg(REG_TXMODE, BIT_RFON, ENABLE); // FORCE 100ask ENABLE
SetReg(REG_TXAMP, AMPLITUDE_A);
SetReg(REG_TXCON, 0x00);
SetReg(REG_RXANA, (HPCF_A << 3) | GAIN_A);
SetReg(0x5F, 0x08);
SetReg(REG_THNSET, 0xFF);
SetReg(REG_THNMIN, 0xC0);
SetReg(REG_RXTXCON, 0x80);
SetParity(ENABLE);
SetReg(REG_STATUS, 0); // 清除Crypto1On位
return SUCCESS;
}
/**
* @brief 初始化读卡器以支持Type B卡片。
* @return 操作状态SUCCESS表示成功。
*/
unsigned char ReaderB_Initial(void)
{
LoadProtocol(RX_TYPEB_106, TX_TYPEB_106);
ModifyReg(REG_TXMODE, BIT_RFON, DISABLE); // FORCE 100ask DISABLE
SetReg(REG_TXAMP, AMPLITUDE_B);
SetReg(REG_TXCON, MODULATION_B);
SetReg(REG_RXANA, (HPCF_B << 3) | GAIN_B);
SetReg(0x5F, 0x08);
SetReg(REG_THNSET, 0xFF);
SetReg(REG_THNMIN, 0xC0);
SetReg(REG_RXTXCON, 0x80);
return SUCCESS;
}
/**
* @brief 初始化读卡器以支持Type V (ISO15693) 卡片。
* @return 操作状态SUCCESS表示成功。
*/
unsigned char ReaderV_Initial(void)
{
LoadProtocol(RX_TYPEV_26, RX_TYPEV_26);
ModifyReg(REG_RXANA, MASK_RCV_GAIN | MASK_RCV_HPCF, DISABLE);
ModifyReg(REG_RXANA, (HPCF_V << 3) | GAIN_V, ENABLE);
SetParity(DISABLE);
SetReg(REG_TXAMP, AMPLITUDE_V);
SetReg(REG_TXCON, MODULATION_V);
SetReg(REG_TXI, 0x06);
SetReg(REG_THNSET, 0xFF);
SetReg(REG_THNMIN, 0x80);
SetReg(REG_THNADJ, 0x08);
SetReg(REG_RXTXCON, 0);
return SUCCESS;
}
/**
* @brief 初始化读卡器以支持Type F (FeliCa) 卡片。
* @return 操作状态SUCCESS表示成功。
*/
unsigned char ReaderF_Initial(void)
{
ModifyReg(REG_MISC, 0x04, ENABLE);
LoadProtocol(RX_FELICA_212, TX_FELICA_212);
SetReg(REG_TXAMP, AMPLITUDE_F);
SetReg(REG_TXCON, MODULATION_F);
ModifyReg(REG_RXANA, MASK_RCV_GAIN | MASK_RCV_HPCF, DISABLE);
ModifyReg(REG_RXANA, (HPCF_F << 3) | GAIN_F, ENABLE);
SetParity(DISABLE);
SetReg(REG_THNSET, 0xFF);
SetReg(REG_THNMIN, 0x80);
SetReg(REG_THNADJ, 0x08);
ModifyReg(REG_MISC, 0x04, DISABLE);
return SUCCESS;
}
/**
* @brief 向Type A卡片发送WUPAWake-Up A命令。
* @param picc_a [out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderA_Wakeeup(struct picc_a_struct *picc_a)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x0F);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, RF_CMD_WUPA);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, DISABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, DISABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(2);
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 2)
return FAIL;
GetReg(REG_FIFODATA, &picc_a->ATQA[0]);
GetReg(REG_FIFODATA, &picc_a->ATQA[1]);
return SUCCESS;
}
/**
* @brief 向Type A卡片发送REQARequest A命令。
* @param picc_a [out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderA_Request(struct picc_a_struct *picc_a)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x0F);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, RF_CMD_REQA);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, DISABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, DISABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(2);
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 2)
return FAIL;
GetReg(REG_FIFODATA, &picc_a->ATQA[0]);
GetReg(REG_FIFODATA, &picc_a->ATQA[1]);
return SUCCESS;
}
/**
* @brief 执行Type A卡片的防冲突流程。
* @param picc_a [in, out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderA_Anticoll(struct picc_a_struct *picc_a)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, RF_CMD_ANTICOLL[picc_a->CASCADE_LEVEL]);
SetReg(REG_FIFODATA, 0x20);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, DISABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, DISABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(2);
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 5)
return FAIL;
GetReg(REG_FIFODATA, &picc_a->UID[picc_a->CASCADE_LEVEL * 4]);
GetReg(REG_FIFODATA, &picc_a->UID[picc_a->CASCADE_LEVEL * 4 + 1]);
GetReg(REG_FIFODATA, &picc_a->UID[picc_a->CASCADE_LEVEL * 4 + 2]);
GetReg(REG_FIFODATA, &picc_a->UID[picc_a->CASCADE_LEVEL * 4 + 3]);
GetReg(REG_FIFODATA, &picc_a->BCC[picc_a->CASCADE_LEVEL]);
if ((picc_a->UID[picc_a->CASCADE_LEVEL * 4] ^ picc_a->UID[picc_a->CASCADE_LEVEL * 4 + 1] ^ picc_a->UID[picc_a->CASCADE_LEVEL * 4 + 2] ^ picc_a->UID[picc_a->CASCADE_LEVEL * 4 + 3]) == picc_a->BCC[picc_a->CASCADE_LEVEL])
return SUCCESS;
return FAIL;
}
/**
* @brief 选择一个已经过防冲突的Type A卡片。
* @param picc_a [in, out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderA_Select(struct picc_a_struct *picc_a)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, RF_CMD_ANTICOLL[picc_a->CASCADE_LEVEL]);
SetReg(REG_FIFODATA, 0x70);
SetReg(REG_FIFODATA, picc_a->UID[picc_a->CASCADE_LEVEL * 4]);
SetReg(REG_FIFODATA, picc_a->UID[picc_a->CASCADE_LEVEL * 4 + 1]);
SetReg(REG_FIFODATA, picc_a->UID[picc_a->CASCADE_LEVEL * 4 + 2]);
SetReg(REG_FIFODATA, picc_a->UID[picc_a->CASCADE_LEVEL * 4 + 3]);
SetReg(REG_FIFODATA, picc_a->BCC[picc_a->CASCADE_LEVEL]);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(2);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 1)
return FAIL;
GetReg(REG_FIFODATA, &picc_a->SAK[picc_a->CASCADE_LEVEL]);
return SUCCESS;
}
/**
* @brief 激活Type A卡片完成REQA, Anticoll, Select全过程
* @param picc_a [out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderA_CardActivate(struct picc_a_struct *picc_a)
{
unsigned char result, cascade_level;
result = ReaderA_Request(picc_a);
if (result != SUCCESS)
return result;
if ((picc_a->ATQA[0] & 0xC0) == 0x00) // 单倍UID
{
cascade_level = 1;
picc_a->UID_Length = 4;
}
else if ((picc_a->ATQA[0] & 0xC0) == 0x40) // 双倍UID
{
cascade_level = 2;
picc_a->UID_Length = 7; // 实际是7字节
}
else if ((picc_a->ATQA[0] & 0xC0) == 0x80) // 三倍UID
{
cascade_level = 3;
picc_a->UID_Length = 10; // 实际是10字节
}
else
{
return FAIL; // 未知UID长度
}
for (picc_a->CASCADE_LEVEL = 0; picc_a->CASCADE_LEVEL < cascade_level; picc_a->CASCADE_LEVEL++)
{
result = ReaderA_Anticoll(picc_a);
if (result != SUCCESS)
return result;
result = ReaderA_Select(picc_a);
if (result != SUCCESS)
return result;
}
picc_a->CASCADE_LEVEL--;
return result;
}
/**
* @brief 向Type B卡片发送WUPBWake-Up B命令。
* @param picc_b [out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderB_Wakeup(struct picc_b_struct *picc_b)
{
unsigned char reg_data, i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, 0x05); // APf
SetReg(REG_FIFODATA, 0x00); // AFI (00:for all cards)
SetReg(REG_FIFODATA, 0x08); // PARAM(WUPB, Number of slots = 0)
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(10);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 12)
return FAIL;
for (i = 0; i < 12; i++)
GetReg(REG_FIFODATA, &picc_b->ATQB[i]);
memcpy(picc_b->PUPI, picc_b->ATQB + 1, 4);
memcpy(picc_b->APPLICATION_DATA, picc_b->ATQB + 6, 4);
memcpy(picc_b->PROTOCOL_INF, picc_b->ATQB + 10, 3);
return SUCCESS;
}
/**
* @brief 向Type B卡片发送REQBRequest B命令。
* @param picc_b [out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderB_Request(struct picc_b_struct *picc_b)
{
unsigned char reg_data, i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, 0x05); // APf
SetReg(REG_FIFODATA, 0x00); // AFI (00:for all cards)
SetReg(REG_FIFODATA, 0x00); // PARAM(REQB, Number of slots = 0)
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(10);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 12)
return FAIL;
for (i = 0; i < 12; i++)
GetReg(REG_FIFODATA, &picc_b->ATQB[i]);
memcpy(picc_b->PUPI, picc_b->ATQB + 1, 4);
memcpy(picc_b->APPLICATION_DATA, picc_b->ATQB + 6, 4);
memcpy(picc_b->PROTOCOL_INF, picc_b->ATQB + 10, 3);
return SUCCESS;
}
/**
* @brief 向Type B卡片发送ATTRIB命令以选择卡片并设置通信参数。
* @param picc_b [in, out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderB_Attrib(struct picc_b_struct *picc_b)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, 0x1D);
SetReg(REG_FIFODATA, picc_b->PUPI[0]);
SetReg(REG_FIFODATA, picc_b->PUPI[1]);
SetReg(REG_FIFODATA, picc_b->PUPI[2]);
SetReg(REG_FIFODATA, picc_b->PUPI[3]);
SetReg(REG_FIFODATA, 0x00); // Param1
SetReg(REG_FIFODATA, 0x08); // Param2
SetReg(REG_FIFODATA, 0x01); // COMPATIBLE WITH 14443-4
SetReg(REG_FIFODATA, 0x01); // CID:01
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(10);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 1)
return FAIL;
GetReg(REG_FIFODATA, &reg_data);
picc_b->CID = reg_data & 0x0F;
return SUCCESS;
}
/**
* @brief 向Type B卡片发送HALT命令使其进入休眠状态。
* @param picc_b [in, out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderB_Halt(struct picc_b_struct *picc_b)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, 0x50);
SetReg(REG_FIFODATA, picc_b->PUPI[0]);
SetReg(REG_FIFODATA, picc_b->PUPI[1]);
SetReg(REG_FIFODATA, picc_b->PUPI[2]);
SetReg(REG_FIFODATA, picc_b->PUPI[3]);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(10);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 1)
return FAIL;
GetReg(REG_FIFODATA, &reg_data);
*picc_b->Answer_to_HALT = reg_data & 0x0F;
return SUCCESS;
}
/**
* @brief 获取Type B卡片的序列号这是一个自定义命令非标准
* @param picc_b [out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderB_Get_SN(struct picc_b_struct *picc_b)
{
unsigned char reg_data, i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, 0x00);
SetReg(REG_FIFODATA, 0x36);
SetReg(REG_FIFODATA, 0x00);
SetReg(REG_FIFODATA, 0x00);
SetReg(REG_FIFODATA, 0x08);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(10);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 10)
return FAIL;
for (i = 0; i < 8; i++)
GetReg(REG_FIFODATA, &picc_b->SN[i]);
return SUCCESS;
}
/**
* @brief 向Type V (ISO15693) 卡片发送Inventory命令。
* @param picc_v [out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderV_Inventory(struct picc_v_struct *picc_v)
{
unsigned char reg_data, i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, 0x26);
SetReg(REG_FIFODATA, 0x01);
SetReg(REG_FIFODATA, 0x00);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(10);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 10)
return FAIL;
GetReg(REG_FIFODATA, &picc_v->RESPONSE);
GetReg(REG_FIFODATA, &reg_data); // DSFID
for (i = 0; i < 8; i++)
{
GetReg(REG_FIFODATA, &picc_v->UID[i]);
}
return SUCCESS;
}
/**
* @brief 选择一个已获取UID的Type V卡片。
* @param picc_v [in, out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderV_Select(struct picc_v_struct *picc_v)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, 0x22); // Addressed flag
SetReg(REG_FIFODATA, 0x25); // Select command
SetReg(REG_FIFODATA, picc_v->UID[0]);
SetReg(REG_FIFODATA, picc_v->UID[1]);
SetReg(REG_FIFODATA, picc_v->UID[2]);
SetReg(REG_FIFODATA, picc_v->UID[3]);
SetReg(REG_FIFODATA, picc_v->UID[4]);
SetReg(REG_FIFODATA, picc_v->UID[5]);
SetReg(REG_FIFODATA, picc_v->UID[6]);
SetReg(REG_FIFODATA, picc_v->UID[7]);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(10);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 1)
return FAIL;
GetReg(REG_FIFODATA, &picc_v->RESPONSE);
return SUCCESS;
}
/**
* @brief 读取Type V卡片的单个数据块。
* @param block_num [in] 要读取的块号。
* @param picc_v [out] 指向存储卡片信息的结构体,读取的数据将存入 `BLOCK_DATA`。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderV_ReadSingleBlock(unsigned char block_num, struct picc_v_struct *picc_v)
{
unsigned char reg_data, i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, 0x02); // Addressed flag
SetReg(REG_FIFODATA, 0x20); // Read Single Block command
SetReg(REG_FIFODATA, block_num);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(10);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 5) // 1 byte response flag + 4 bytes data
return FAIL;
GetReg(REG_FIFODATA, &picc_v->RESPONSE);
for (i = 0; i < 4; i++)
{
GetReg(REG_FIFODATA, &picc_v->BLOCK_DATA[i]);
}
return SUCCESS;
}
/**
* @brief 向Type V卡片的单个数据块写入数据。
* @param block_num [in] 要写入的块号。
* @param picc_v [in] 指向存储卡片信息的结构体,要写入的数据在 `BLOCK_DATA` 中。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderV_WriteSingleBlock(unsigned char block_num, struct picc_v_struct *picc_v)
{
unsigned char reg_data;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, 0x02); // Addressed flag
SetReg(REG_FIFODATA, 0x21); // Write Single Block command
SetReg(REG_FIFODATA, block_num);
SetReg(REG_FIFODATA, picc_v->BLOCK_DATA[0]);
SetReg(REG_FIFODATA, picc_v->BLOCK_DATA[1]);
SetReg(REG_FIFODATA, picc_v->BLOCK_DATA[2]);
SetReg(REG_FIFODATA, picc_v->BLOCK_DATA[3]);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(10);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 1)
return FAIL;
GetReg(REG_FIFODATA, &picc_v->RESPONSE);
return SUCCESS;
}
/**
* @brief 向Type F (FeliCa) 卡片发送Inventory命令。
* @param picc_f [out] 指向存储卡片信息的结构体。
* @return 操作状态SUCCESS表示成功FAIL表示失败。
*/
unsigned char ReaderF_Inventory(struct picc_f_struct *picc_f)
{
unsigned char reg_data, i;
SetCommand(CMD_IDLE);
SetReg(REG_TXDATANUM, 0x08);
ModifyReg(REG_FIFOCONTROL, BIT_FIFOFLUSH, ENABLE);
SetReg(REG_FIFODATA, 0x06);
SetReg(REG_FIFODATA, 0x00);
SetReg(REG_FIFODATA, 0xFF);
SetReg(REG_FIFODATA, 0xFF);
SetReg(REG_FIFODATA, 0x10);
SetReg(REG_FIFODATA, 0x00);
ModifyReg(REG_TXCRCCON, BIT_CRCEN, ENABLE);
ModifyReg(REG_RXCRCCON, BIT_CRCEN, ENABLE);
SetCommand(CMD_TRANSCEIVE);
rfid_delay_ms(10);
GetReg(REG_ERROR, &reg_data);
if ((reg_data & 0x0F) != 0)
return FAIL;
GetReg(REG_FIFOLENGTH, &reg_data);
if (reg_data != 18)
return FAIL;
GetReg(REG_FIFODATA, &reg_data); // Length
GetReg(REG_FIFODATA, &reg_data); // Response code
for (i = 0; i < 8; i++)
{
GetReg(REG_FIFODATA, &picc_f->UID[i]);
}
return SUCCESS;
}

View File

@ -0,0 +1,306 @@
/********************************************************************************************************
* @file rfid_main.c
* @brief RFID 读卡器应用层主逻辑文件
********************************************************************************************************/
#include "./include/rfid_main.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "./include/READER.h"
#include "./include/READER_REG.h"
#include "./include/MIFARE.h"
#include "./include/NTAG.h"
#include "./include/CPU_CARD.h"
#include "./rfid_hal.h"
#define ENABLE_XLOG 1
#ifdef xlog
#undef xlog
#endif
#if ENABLE_XLOG
#define xlog(format, ...) printf("[XT:%s] " format, __func__, ##__VA_ARGS__)
#else
#define xlog(format, ...) ((void)0)
#endif
/**
* @brief 处理Type A卡片事件。
* @details
* 该函数执行ISO/IEC 14443 Type A卡片的完整激活流程包括
* 1. 初始化读卡器以支持Type A协议。
* 2. 打开RF场。
* 3. 请求Request和防冲突Anticollision最终激活卡片。
* 4. 根据卡片的SAKSelect Acknowledge判断卡片具体类型如Mifare, NTAG, CPU卡并调用相应的处理函数。
* 5. 操作结束后关闭RF场。
* @return 无。
*/
void TYPE_A_EVENT(void)
{
unsigned char result;
int i;
xlog("TYPE_A_EVENT begin\n");
// 初始化读卡器为Type A模式
result = ReaderA_Initial();
if (result != SUCCESS)
{
xlog("INIT_ERROR\r\n");
SetCW(DISABLE);
return;
}
// 打开RF场载波
result = SetCW(ENABLE);
if (result != SUCCESS)
{
xlog("CW_ERROR\r\n");
SetCW(DISABLE);
return;
}
// 激活Type A卡片
result = ReaderA_CardActivate(&PICC_A);
if (result != SUCCESS)
{
// xlog("ReaderA_CardActivate_ERROR\r\n");
SetCW(DISABLE);
return;
}
xlog("************* TYPE A CARD ************* \r\n");
xlog("-> ATQA = %02X%02X\r\n", PICC_A.ATQA[0], PICC_A.ATQA[1]);
if (PICC_A.UID_Length > 0)
{
xlog("-> UID = ");
for (i = 0; i < PICC_A.UID_Length; i++)
{
xlog("%02X", PICC_A.UID[i]);
}
xlog("\r\n");
}
xlog("-> SAK = %02X\r\n", PICC_A.SAK[0]);
// 根据SAK值判断卡片类型
if (PICC_A.SAK[0] == 0x08)
{
xlog("************* Mifare CARD ************* \r\n");
result = MIFARE_CARD_EVENT();
}
else if ((PICC_A.SAK[0] == 0x28) || (PICC_A.SAK[0] == 0x20))
{
xlog("************* CPU CARD ************* \r\n");
result = CPU_CARD_EVENT();
}
else if (PICC_A.SAK[0] == 0x04)
{
xlog("************* NTAG CARD ************* \r\n");
result = NTAG_EVENT();
}
SetCW(DISABLE); // 关闭RF场
}
/**
* @brief 处理Type B卡片事件。
* @details
* 该函数执行ISO/IEC 14443 Type B卡片的激活流程包括
* 1. 初始化读卡器以支持Type B协议。
* 2. 打开RF场。
* 3. 发送REQB/WUPB命令寻卡。
* 4. 发送ATTRIB命令选卡。
* 5. 获取卡片序列号SN
* 6. 操作结束后关闭RF场。
* @return 无。
*/
void TYPE_B_EVENT(void)
{
unsigned char result;
int i;
xlog("TYPE_B_EVENT begin\n");
ReaderB_Initial();
SetCW(ENABLE);
result = ReaderB_Request(&PICC_B);
if (result != SUCCESS)
{
SetCW(DISABLE);
return;
}
xlog("************* TYPE B CARD ************* \r\n");
// 打印ATQB信息
xlog("-> ATQB = ");
for(i=0; i<12; i++) xlog("%02X", PICC_B.ATQB[i]);
xlog("\r\n");
result = ReaderB_Attrib(&PICC_B);
if (result != SUCCESS)
{
SetCW(DISABLE);
return;
}
xlog("-> ATTRIB = %02X\r\n", PICC_B.CID);
result = ReaderB_Get_SN(&PICC_B);
if (result != SUCCESS)
{
SetCW(DISABLE);
return;
}
xlog("-> SN = ");
for(i=0; i<8; i++) xlog("%02X", PICC_B.SN[i]);
xlog("\r\n");
SetCW(DISABLE);
}
/**
* @brief 处理Type V (ISO/IEC 15693) 卡片事件。
* @details
* 该函数执行ISO/IEC 15693 Vicinity卡片的交互流程包括
* 1. 初始化读卡器以支持15693协议。
* 2. 打开RF场。
* 3. 发送Inventory命令寻卡并获取UID。
* 4. 发送Select命令选择卡片。
* 5. 示例性地对第4块进行写操作然后再读回校验。
* 6. 操作结束后关闭RF场。
* @return 无。
*/
void TYPE_V_EVENT(void)
{
unsigned char result, i;
xlog("TYPE_V_EVENT begin\n");
ReaderV_Initial();
SetCW(ENABLE);
result = ReaderV_Inventory(&PICC_V);
if (result != SUCCESS)
{
SetCW(DISABLE);
xlog("-> ReaderV Inventory ERROR!\r\n");
return;
}
xlog("************* TYPE V CARD ************* \r\n");
xlog("UID=");
for (i = 0; i < 8; i++)
{
xlog("%02X", PICC_V.UID[i]);
}
xlog("\r\n");
result = ReaderV_Select(&PICC_V);
if (result != SUCCESS)
{
SetCW(DISABLE);
xlog("-> ReaderV Select ERROR!\r\n");
return;
}
// 示例:写单个块
memcpy(PICC_V.BLOCK_DATA, "\x11\x22\x33\x44", 4);
result = ReaderV_WriteSingleBlock(4, &PICC_V);
if (result != SUCCESS)
{
SetCW(DISABLE);
xlog("-> ReaderV WriteSingleBlock ERROR!\r\n");
return;
}
xlog("WriteSingleBlock SUCCESS\r\n");
// 示例:读单个块
result = ReaderV_ReadSingleBlock(4, &PICC_V);
if (result != SUCCESS)
{
SetCW(DISABLE);
xlog("-> ReaderV ReadSingleBlock ERROR!\r\n");
return;
}
xlog("BLOCK DATA = %02X%02X%02X%02X \r\n", PICC_V.BLOCK_DATA[0], PICC_V.BLOCK_DATA[1], PICC_V.BLOCK_DATA[2], PICC_V.BLOCK_DATA[3]);
SetCW(DISABLE);
}
/**
* @brief 处理Type F (FeliCa) 卡片事件。
* @details
* 该函数执行FeliCa卡片的交互流程包括
* 1. 初始化读卡器以支持FeliCa协议。
* 2. 打开RF场。
* 3. 发送Inventory命令寻卡并获取UID。
* 4. 后续可以添加与FeliCa卡的数据交换命令。
* 5. 操作结束后关闭RF场。
* @note 当前实现仅包含寻卡部分。
* @return 无。
*/
void TYPE_F_EVENT(void)
{
unsigned char result, i;
xlog("TYPE_F_EVENT begin\n");
ReaderF_Initial();
SetCW(ENABLE);
result = ReaderF_Inventory(&PICC_F);
if (result != SUCCESS)
{
SetCW(DISABLE);
return;
}
xlog("************* TYPE F CARD ************* \r\n");
xlog("->TYPE F UID = ");
for(i=0; i<8; i++) xlog("%02X", PICC_F.UID[i]);
xlog("\r\n");
SetCW(DISABLE);
}
/**
* @brief RFID模块的主任务函数。
* @details
* 利用定时器调用
* @return 无。
*/
void rfid_task_fuc(void)
{
unsigned char result, reg_data;
static u8 first_init = 0;
if(first_init == 0){
first_init = 1;
rfid_hal_init();
// 2. 复位 FM176XX 芯片
while (1)
{
result = FM176XX_SoftReset();
if (result != SUCCESS)
{
xlog("FM176XX HardReset FAIL\r\n");
rfid_delay_ms(1000); // 延时后重试
}
else
{
xlog("FM176XX HardReset SUCCESS\r\n");
break;
}
}
}
// 3. 读取芯片版本号,确认通信是否正常
GetReg(REG_VERSION, &reg_data);
xlog("REG_VERSION = %02X\r\n", reg_data);
TYPE_A_EVENT();
TYPE_B_EVENT();
TYPE_V_EVENT();
TYPE_F_EVENT();
}

View File

@ -0,0 +1,81 @@
#include "./rfid_hal.h"
#include "gSensor/gSensor_manage.h"
#include "./include/rfid_main.h"
#include "./include/READER_REG.h"
#define INTERFACE_TYPE 0
//////////////////////////////////////////////////////////////////////////////////////////////////
//
#if INTERFACE_TYPE == 0 //iic接口
/*
IF2 IF0 ADDR
0 0 0x28
0 1 0x29
1 0 0x2A
1 1 0x2B
*/
#define FM176_7BIT_ADDR 0x28 //后两位地址由IF2、IF1决定
#define FM176_READ_ADDR (FM176_7BIT_ADDR << 1)
#define FM176_WRITE_ADDR ((FM176_7BIT_ADDR << 1) | 0x01)
unsigned char FM176XX_HardInit(void){
int ret = hw_iic_init(0);
xlog("init iic result:%d\n", ret); //返回0成功
}
/**
* @brief 从FM176XX芯片读取一个字节的寄存器值。
* @param address [in] 目标寄存器的地址。
* @param reg_data [out] 指向用于存储读取数据的字节的指针。
* @return 操作状态SUCCESS表示成功。
* @details
* 接口iic
*/
unsigned char GetReg(unsigned char address, unsigned char *reg_data){
if(_gravity_sensor_get_ndata(FM176_READ_ADDR, address, reg_data, 1)){
return SUCCESS;
}else{
return FAIL;
}
}
/**
* @brief 向FM176XX芯片写入一个字节的寄存器值。
* @param address [in] 目标寄存器的地址。
* @param reg_data [in] 要写入的字节数据。
* @return 操作状态SUCCESS表示成功。
* @details
* 接口iic
*/
unsigned char SetReg(unsigned char address, unsigned char reg_data){
if(gravity_sensor_command(FM176_WRITE_ADDR, address, reg_data) == 0){
return FAIL;
}else{
return SUCCESS;
}
}
/**
* @brief 软件复位命令0x1F
*
* @return unsigned char
*/
unsigned char FM176XX_SoftReset(void){
gravity_sensor_command(FM176_WRITE_ADDR,REG_COMMAND,0x1F);
}
#elif INTERFACE_TYPE == 1 //spi
#elif INTERFACE_TYPE == 2 //uart
#endif
void rfid_delay_ms(unsigned int ms){
os_time_dly(ms/10);
}

View File

@ -0,0 +1,76 @@
/********************************************************************************************************
* @file rfid_hal.h
* @brief RFID 硬件抽象层 (HAL) 接口定义
* @details
*
********************************************************************************************************/
#ifndef RFID_HAL_H
#define RFID_HAL_H
#include "system/includes.h"
/********************************************************************************************************
* 函数原型声明
********************************************************************************************************/
/**
* @brief 从FM176XX芯片读取一个字节的寄存器值。
* @param address [in] 目标寄存器的地址。
* @param reg_data [out] 指向用于存储读取数据的字节的指针。
* @return 操作状态SUCCESS表示成功。
* @details
* 接口uart、iic、spi
* 自行实现
*/
unsigned char GetReg(unsigned char address, unsigned char *reg_data);
/**
* @brief 向FM176XX芯片写入一个字节的寄存器值。
* @param address [in] 目标寄存器的地址。
* @param reg_data [in] 要写入的字节数据。
* @return 操作状态SUCCESS表示成功。
* @details
* 接口uart、iic、spi
* 自行实现
*/
unsigned char SetReg(unsigned char address, unsigned char reg_data);
/**
* @brief 接口硬件初始化
*
* @return unsigned char
*/
unsigned char FM176XX_HardInit(void);
/**
* @brief 硬件复位
* 通过控制RST引脚产生一个低电平脉冲来复位芯片。
* 复位后会读取命令寄存器REG_COMMAND的值进行检查
* 如果值不为0x40则认为复位失败。
*
* @return unsigned char
*/
unsigned char FM176XX_HardReset(void);
/**
* @brief 软件复位命令0x1F
*
* @return unsigned char
*/
unsigned char FM176XX_SoftReset(void);
/**
* @brief 实现一个毫秒级的延时。
* @param ms [in] 要延时的毫秒数。
* @return 无。
* @details
* 一个阻塞式延时函数。
*/
void rfid_delay_ms(unsigned int ms);
#endif // RFID_HAL_H