📄 fm1702.c
字号:
#include <string.h>
#include <stdio.h>
#include <absacc.h>
#include <intrins.h>
#include "FM1702.h"
#include "reg52.h"
#define NO_TIMER2 1
bit CmdValid;
unsigned char cardtype;
//uchar idata readdata[16]; /* 读写数据缓冲区 */
//uchar idata value[4]; /* 增减的数值 */
//uchar idata KeySet; /* 密码类型 */
uchar idata tagtype[2]; /* 卡片标识字符 */
/* FM1715变量定义 */
//uchar idata PRO_SendBuf[16]; /* 发送处理缓冲区16 BYTE */
//uchar idata PRO_RecvBuf[16]; /* 接收处理缓冲区16 BYTE */
uchar idata buffer[30]; /* FM1715命令发送接收缓冲区 */
uchar idata UID[5]; /* 序列号 */
uchar idata Secnr; /* 扇区号 */
/****************************************************************/
/*名称: Clear_FIFO */
/*功能: 该函数实现清空FM1715中FIFO的数据*/
/*输入: N/A */
/*输出: TRUE, FIFO被清空*/
/* FALSE, FIFO未被清空*/
/****************************************************************/
uchar Clear_FIFO(void)
{
/*~~~~~~~~~*/
uchar temp;
uint i;
/*~~~~~~~~~*/
temp = Control; /* 清空FIFO */
temp = (temp | 0x01);
Control = temp;
for(i = 0; i < RF_TimeOut; i++) /* 检查FIFO是否被清空 */
{
temp = FIFO_Length;
if(temp == 0)
{
return TRUE;
}
}
return FALSE;
}
/****************************************************************/
/*名称: Write_FIFO */
/*功能: 该函数实现向FM1715的FIFO中写入x bytes数据*/
/*输入: count, 待写入字节的长度*/
/* buff, 指向待写入数据的指针*/
/*输出: N/A */
/****************************************************************/
void Write_FIFO(uchar count, uchar idata *buff)
{
/*~~~~~~*/
uchar i;
/*~~~~~~*/
for(i = 0; i < count; i++)
{
FIFO = *(buff + i);
}
}
/****************************************************************/
/*名称: Read_FIFO */
/*功能: 该函数实现从FM1715的FIFO中读出x bytes数据*/
/*输入: buff, 指向读出数据的指针*/
/*输出: N/A */
/****************************************************************/
uchar Read_FIFO(uchar idata *buff)
{
/*~~~~~~~~~*/
uchar temp;
uchar i;
/*~~~~~~~~~*/
temp = FIFO_Length;
if(temp == 0)
{
return 0;
}
if(temp >= 24) /* temp=255时,会进入死循环 */
{
/* 因此增加FIFO_Length越限判断 */
temp = 24; /* yanshouli,2003-12-2 */
}
for(i = 0; i < temp; i++)
{
*(buff + i) = FIFO;
}
return temp;
}
/****************************************************************/
/*名称: Judge_Req */
/*功能: 该函数实现对卡片复位应答信号的判断*/
/*输入: *buff, 指向应答数据的指针*/
/*输出: TRUE, 卡片应答信号正确*/
/* FALSE, 卡片应答信号错误*/
/****************************************************************/
uchar Judge_Req(uchar idata *buff)
{
/*~~~~~~~~~~~~~~~~~*/
uchar temp1, temp2;
/*~~~~~~~~~~~~~~~~~*/
temp1 = *buff;
temp2 = *(buff + 1);
if(((temp1 == 0x03) || (temp1 == 0x04) || (temp1 == 0x05) || (temp1 == 0x53)) && (temp2 == 0x00))
{
return TRUE;
}
return FALSE;
}
/****************************************************************/
/*名称: Check_UID */
/*功能: 该函数实现对收到的卡片的序列号的判断*/
/*输入: N/A */
/*输出: TRUE: 序列号正确*/
/* FALSE: 序列号错误*/
/****************************************************************/
uchar Check_UID(void)
{
/*~~~~~~~~~*/
uchar temp;
uchar i;
/*~~~~~~~~~*/
temp = 0x00;
for(i = 0; i < 5; i++)
{
temp = temp ^ UID[i];
}
if(temp == 0)
{
return TRUE;
}
return FALSE;
}
/****************************************************************/
/*名称: Save_UID */
/*功能: 该函数实现保存卡片收到的序列号*/
/*输入: row: 产生冲突的行*/
/* col: 产生冲突的列*/
/* length: 接収到的UID数据长度*/
/*输出: N/A */
/****************************************************************/
void Save_UID(uchar row, uchar col, uchar length)
{
/*~~~~~~~~~~*/
uchar i;
uchar temp;
uchar temp1;
/*~~~~~~~~~~*/
if((row == 0x00) && (col == 0x00))
{
for(i = 0; i < length; i++)
{
UID[i] = buffer[i];
}
}
else
{
temp = buffer[0];
temp1 = UID[row - 1];
switch(col)
{
case 0: temp1 = 0x00; row = row + 1; break;
case 1: temp = temp & 0xFE; temp1 = temp1 & 0x01; break;
case 2: temp = temp & 0xFC; temp1 = temp1 & 0x03; break;
case 3: temp = temp & 0xF8; temp1 = temp1 & 0x07; break;
case 4: temp = temp & 0xF0; temp1 = temp1 & 0x0F; break;
case 5: temp = temp & 0xE0; temp1 = temp1 & 0x1F; break;
case 6: temp = temp & 0xC0; temp1 = temp1 & 0x3F; break;
case 7: temp = temp & 0x80; temp1 = temp1 & 0x7F; break;
default: break;
}
buffer[0] = temp;
UID[row - 1] = temp1 | temp;
for(i = 1; i < length; i++)
{
UID[row - 1 + i] = buffer[i];
}
}
}
/****************************************************************/
/*名称: Set_BitFraming */
/*功能: 该函数设置待发送数据的字节数*/
/*输入: row: 产生冲突的行*/
/* col: 产生冲突的列*/
/*输出: N/A */
/****************************************************************/
void Set_BitFraming(uchar row, uchar col)
{
switch(row)
{
case 0: buffer[1] = 0x20; break;
case 1: buffer[1] = 0x30; break;
case 2: buffer[1] = 0x40; break;
case 3: buffer[1] = 0x50; break;
case 4: buffer[1] = 0x60; break;
default: break;
}
switch(col)
{
case 0: Bit_Frame = 0x00; break;
case 1: Bit_Frame = 0x11; buffer[1] = (buffer[1] | 0x01); break;
case 2: Bit_Frame = 0x22; buffer[1] = (buffer[1] | 0x02); break;
case 3: Bit_Frame = 0x33; buffer[1] = (buffer[1] | 0x03); break;
case 4: Bit_Frame = 0x44; buffer[1] = (buffer[1] | 0x04); break;
case 5: Bit_Frame = 0x55; buffer[1] = (buffer[1] | 0x05); break;
case 6: Bit_Frame = 0x66; buffer[1] = (buffer[1] | 0x06); break;
case 7: Bit_Frame = 0x77; buffer[1] = (buffer[1] | 0x07); break;
default: break;
}
}
/****************************************************************/
/*名称: FM1715_Bus_Sel */
/*功能: 该函数实现对FM1715操作的总线方式(并行总线,SPI)选择*/
/*输入: N/A */
/*输出: TRUE, 总线选择成功*/
/* FALSE, 总线选择失败*/
/****************************************************************/
uchar FM1715_Bus_Sel(void)
{
/*~~~~~~*/
uchar i;
/*~~~~~~*/
Page_Sel = 0x80; /* 表示PageSelect的值做为寄存器地址A5A4 和A3低 */
/* 三位寄存器地址A2A0 由//外部地址线A2A0 决定 */
for(i = 0; i < RF_TimeOut; i++) /* 延时 */
{
if(Command == 0x00) /* 读命令执行结果, bit7为0表示接口检测结束 */
{
Page_Sel = 0x00;
return TRUE;
}
}
return FALSE;
}
/****************************************************************/
/*名称: Init_FM1715 */
/*功能: 该函数实现对FM1715初始化操作*/
/*输入: mode:工作模式, 0:TYPEA模式*/
/* 1:TYPEB模式*/
/* 2:上海模式*/
/*输出: N/A */
/****************************************************************/
void Init_FM1715(uchar mode)
{
/*~~~~~~~~~~~~~~~~~*/
uchar idata temp;
uint i;
/*~~~~~~~~~~~~~~~~~*/
MFRST = 1; /* FM1715复位 */
for(i = 0; i < 0x1fff; i++)
{
_nop_();
}
MFRST = 0;
for(i = 0; i < 0x1fff; i++)
{
_nop_();
}
while(Command != 0) /* 等待Command = 0,FM1715复位成功 */
{
_nop_();
}
temp = FM1715_Bus_Sel(); /* FM1715总线选择 */
TimerClock = 0x0b; /* 151us/per */
TimerControl = 0x02; /* 发送结束开定时器接收开始关定时器 */
TimerReload = 0x42; /* 10ms定时 */
InterruptEn = 0x7f; /* 关所有中断 */
temp = InterruptEn;
Int_Req = 0x7f;
MFOUTSelect = 0x02; /* 调试用 */
TxControl = 0x5b; /* 开启TX1TX2 */
if(mode == SHANGHAI_MODE) /* 上海模式 */
{
TypeSH = 0x01;
}
else
{
TypeSH = 0x00;
}
if(mode == TYPEB_MODE) /* TYPEB模式 */
{
CoderControl = 0x20;
TypeBFraming = 0x05;
DecoderControl = 0x19;
ChannelRedundancy = 0x24;
TxControl = 0x4b;
CWConductance = 0x3f;
ModConductance = 0xaf;
}
}
/****************************************************************/
/*名称: Command_Send */
/*功能: 该函数实现向FM1715发送命令集的功能*/
/*输入: count, 待发送命令集的长度*/
/* buff, 指向待发送数据的指针*/
/* Comm_Set, 命令码*/
/*输出: TRUE, 命令被正确执行*/
/* FALSE, 命令执行错误*/
/****************************************************************/
uchar Command_Send(uchar count, uchar idata *buff, uchar Comm_Set)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~*/
uint j;
uchar idata temp, temp1;
/*~~~~~~~~~~~~~~~~~~~~~~~~*/
Command = 0x00;
Clear_FIFO();
Write_FIFO(count, buff);
temp = MFOUTSelect;
Command = Comm_Set; /* 命令执行 */
for(j = 0; j < RF_TimeOut; j++) /* 检查命令执行否 */
{
temp = MFOUTSelect;
temp = Command;
temp1 = Int_Req & 0x80;
if((temp == 0x00) || (temp1 == 0x80))
{
return TRUE;
}
}
return FALSE;
}
/****************************************************************/
/*名称: Read_E2 */
/*功能: 该函数实现从FM1715的EE中读出数据*/
/*输入: lsb, EE地址(低字节) */
/* msb, EE地址(高字节) */
/* count, 待读出数据EE的字节个数*/
/* buff, 指向待读出数据的指针*/
/*输出: TRUE, EE数据正确读出*/
/* FALSE, EE数据读出有误*/
/****************************************************************/
uchar Read_E2(uchar lsb, uchar msb, uchar count, uchar idata *buff)
{
/*~~~~~~~~~*/
uchar temp;
/*~~~~~~~~~*/
*buff = lsb;
*(buff + 1) = msb;
*(buff + 2) = count;
temp = Command_Send(3, buff, ReadE2);
Read_FIFO(buff);
if(temp == FALSE) return(TRUE);
return(FALSE);
}
/****************************************************************/
/*名称: Write_E2 */
/*功能: 该函数实现向FM1715的EE中写入数据*/
/*输入: lsb, EE地址(低字节) */
/* msb, EE地址(高字节) */
/* count, 待写入数据EE的字节个数*/
/* buff, 指向待写入数据的指针*/
/*输出: TRUE, EE数据正确写入*/
/* FALSE, EE数据写入有误*/
/****************************************************************/
uchar Write_E2(uchar lsb, uchar msb, uchar count, uchar idata *buff)
{
/*~~~~~~~~~~~~~~~~~~~~*/
uchar idata temp, i;
/*~~~~~~~~~~~~~~~~~~~~*/
for(i = 0; i < count; i++)
{
*(buff + count - i + 2) = *(buff - i + count);
}
*buff = lsb;
*(buff + 1) = msb;
temp = Command_Send(count + 2, buff, WriteE2);
temp = SecondaryStatus;
temp = temp & 0x40;
if(temp == 0x40)
{
return TRUE;
}
return FALSE;
}
/****************************************************************/
/*名称: MIF_Halt */
/*功能: 该函数实现暂停MIFARE卡*/
/*输入: N/A */
/*输出: FM1715_OK: 应答正确*/
/* FM1715_PARITYERR: 奇偶校验错*/
/* FM1715_CRCERR: CRC校验错*/
/* FM1715_NOTAGERR: 无卡*/
/****************************************************************/
uchar MIF_Halt(void)
{
/*~~~~~~~~~*/
uchar temp;
uint i;
/*~~~~~~~~~*/
CRCPresetLSB = 0x63;
CWConductance = 0x3f;
ChannelRedundancy = 0x03;
*buffer = RF_CMD_HALT;
*(buffer + 1) = 0x00;
temp = Command_Send(2, buffer, Transmit);
if(temp == TRUE)
{
for(i = 0; i < 0x50; i++)
{
_nop_();
}
return FM1715_OK;
}
else
{
temp = ErrorFlag;
if((temp & 0x02) == 0x02)
{
return(FM1715_PARITYERR);
}
if((temp & 0x04) == 0x04)
{
return(FM1715_FRAMINGERR);
}
return(FM1715_NOTAGERR);
}
}
///////////////////////////////////////////////////////////////////////
// 转换密钥格式
///////////////////////////////////////////////////////////////////////
char M500HostCodeKey(unsigned char *uncoded, unsigned char *coded)
{
char idata status = FM1715_OK;
unsigned char idata cnt = 0;
unsigned char idata ln = 0;
unsigned char idata hn = 0;
for (cnt = 0; cnt < 6; cnt++)
{
ln = uncoded[cnt] & 0x0F;
hn = uncoded[cnt] >> 4;
coded[cnt * 2 + 1] = (~ln << 4) | ln;
coded[cnt * 2 ] = (~hn << 4) | hn;
}
return FM1715_OK;
}
/****************************************************************/
/*名称: Load_keyE2 */
/*功能: 该函数实现把E2中密码存入FM1715的keybuffer中*/
/*输入: Secnr: EE起始地址*/
/*输出: True: 密钥装载成功*/
/* False: 密钥装载失败*/
/****************************************************************/
uchar Load_keyE2_CPY(uchar *uncoded_keys)
{
uchar temp;
unsigned char coded_keys[13];
M500HostCodeKey(uncoded_keys, coded_keys);
temp = Command_Send(12, coded_keys, LoadKey);
temp = ErrorFlag & 0x40;
if (temp == 0x40)
{
return FALSE;
}
return TRUE;
}
/****************************************************************/
/*名称: Request */
/*功能: 该函数实现对放入FM1715操作范围之内的卡片的Request操作*/
/*输入: mode: ALL(监测所以FM1715操作范围之内的卡片) */
/* STD(监测在FM1715操作范围之内处于HALT状态的卡片) */
/*输出: FM1715_NOTAGERR: 无卡*/
/* FM1715_OK: 应答正确*/
/* FM1715_REQERR: 应答错误*/
/****************************************************************/
uchar Request(uchar mode)
{
/*~~~~~~~~~~~~~~~~~*/
uchar idata temp;
/*~~~~~~~~~~~~~~~~~*/
CRCPresetLSB = 0x63;
CWConductance = 0x3f;
buffer[0] = mode; /* Request模式选择 */
Bit_Frame = 0x07; /* 发送7bit */
ChannelRedundancy = 0x03; /* 关闭CRC */
temp = Control;
temp = temp & (0xf7);
Control = temp; /* 屏蔽CRYPTO1位 */
temp = Command_Send(1, buffer, Transceive);
if(temp == FALSE)
{
return FM1715_NOTAGERR;
}
Read_FIFO(buffer); /* 从FIFO中读取应答信息 */
temp = Judge_Req(buffer); /* 判断应答信号是否正确 */
if(temp == TRUE)
{
tagtype[0] = buffer[0];
tagtype[1] = buffer[1];
return FM1715_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -