📄 card_trans.c
字号:
/*-------------------------------------------------------------
功能:卡的数据传输(命令响应结构)
说明:符合国家标准GB18240.1-2003和GB18240.2-2003的税控机软件
日期:2003年6月12日
---------------------------------------------------------------*/
#include "include.h"
#define COMMAND_HEAD 0x60
#define ISO_READ 0xDB
#define ISO_WRITE 0xDA
//=================1 通用命令==============================//
/************************************************************
功能: 命令打包,打包后可与IC卡通讯
入口参数:cmd,以\0为结束符的字符串;databuf要打包的数据部分;
datalen,数据长度
le,期望返回数据的长度
出口参数:cmd,打包后的没有结束符的字符指针
包的格式为:包头(0x60)+长度(命令区+数据区的长度+期望返回数据的长度1字节)1字节+命令区+
数据区+期望返回数据的长度1字节
返回值 :打包成功返回0,否则返回其他错误
作者:
**********************************************************************/
uchar pack_cmd(uchar * cmd,uchar* databuf,uchar datalen,uchar le)
{
uchar xdata str[200];
uchar cmdlen;
uchar rlt;
str[0]=COMMAND_HEAD ; //0x60,卡通讯命令的头
cmdlen=strlen((const char *)cmd)/2; //命令长度
str[1]=cmdlen+datalen;//命令和数据的长度
//if(le>0)
str[1]++;
rlt=HexToByte(cmd,cmd);
if (rlt) //命令字的转换
return(rlt);
if(datalen>0)
memcpy(&cmd[cmdlen],databuf,datalen);
memcpy(&str[2],cmd,str[1]);
memcpy(cmd,str,2+cmdlen+datalen);//+2是包头(1字节)和命令和数据的长度(1字节)
//if(le>0) //返回的数据的长度
cmd[2+cmdlen+datalen]=le;
return(0);
}
/**********************************************************
功能 :从卡的返回数据检查返回是否正确以及返回的有用数据
入口参数:str,卡通讯时返回的数据包
出口参数:str,从返回的数据包中取出的有用数据
包的格式为:包头(0x60)+长度(数据区的长度)1字节+读写模式(1字节)+
数据区+状态字(2字节)
返回值:通讯成功返回0,否则返回CPU卡操作错误
作者:
***********************************************************/
uchar get_data(uchar * str)
{
uchar len;
len=str[1];
//send_str(len+4,str);
if(!(str[len+3]==0x90 && str[len+4]==0x00||
str[len+3]==0x61))
return(CPU_OPERATE_FAIL);
if(len) //有返回数据
memcpy(str,&str[3],len);
return(0);
}
/*-----------------------------------------------------------------
说 明:根据文件标识选择文件(EF或DF均可)
参 数:which_card: ==0,选择税控卡上的文件
==1,选择用户卡上的文件
==2,选择稽查卡上的文件
FileID: 文件标识
返回值:成功返回0,否则返回非0
作 者:
-------------------------------------------------------------------*/
uchar SelFile_id(uchar which_card, uint FileID)
{
uchar xdata cmd[30],cmd2[10];
uchar rlt;
if((which_card!=SAM_CARD)&&(which_card!=USER_CARD)&&(which_card!=CHK_CARD)) //检验入口参数
return (PARAM_FAIL);
strcpy(cmd,"DA00A4000002"); //其中DA表示读卡
cmd2[0]=(FileID>>8)&0xff; //文件标识
cmd2[1]=FileID&0xff;
rlt=pack_cmd(cmd,cmd2,2,0);
if(rlt)
return(rlt);
if(which_card==SAM_CARD) //和税控卡通讯
rlt=sam_iso(cmd);
else // 和用户卡或稽查卡通讯
rlt=id_iso(cmd);
if(rlt)
switch(which_card)
{
case SAM_CARD:
return(SAM_COMM_FAIL);
case USER_CARD:
return(USR_COMM_FAIL);
case CHK_CARD:
return(CHK_COMM_FAIL);
}
//if(testbuf[0]==0xaa)send_str(20,cmd);
rlt=get_data(cmd);
//if(testbuf[0]==0xaa)send_char(rlt);
if(rlt)
switch(which_card)
{
case SAM_CARD:
return(SAM_SEL_FIL_FAIL);
case USER_CARD:
return(USR_SEL_FIL_FAIL);
case CHK_CARD:
return(CHK_SEL_FIL_FAIL);
}
return 0;
}
/*--------------------------------------------------------------------------
说 明:读取当前变长文件的某条记录,先选择文件使得操作针对当前文件,
按记录标识来读
注 意: 本函数在调用之前需先选择某文件
参 数:card_type: 0,税控卡 ;1,用户卡,2 稽查卡
file_type: 0,变长记录文件 1,定长记录文件
record: 变长记录文件时是记录标识
定长记录文件时为记录号
len: 需要读取的记录的实际长度
content: 如果成功,为返回的数据
返回值: 0,成功; 其他,失败
作 者:
--------------------------------------------------------------------------*/
uchar ReadRec(uchar card_type, uchar file_type, uchar record, uchar len, uchar xdata *content)
{
uchar xdata buf[200];// 数组的长度根据需要调整,每条记录最长也只有178字节
uchar xdata i;
// 对输入参数合法性检查
if((card_type!=SAM_CARD)&&(card_type!=USER_CARD)&&(card_type!=CHK_CARD))
return (PARAM_FAIL);
if((file_type!=0)&&(file_type!=1))
{
return (PARAM_FAIL);
}
/*buf[0]=0x60;
buf[1]=6;
buf[2]=ISO_READ;
buf[3]=0x00; // CLA
buf[4]=0xB2; // INS
buf[5]=record; // P1 记录标识
buf[6]= 0x04; //P2 当前文件
buf[7]= len;
*/
strcpy(buf,"DB00B20104");
pack_cmd(buf,"",0,len); //lyj
buf[5]=record; // P1 记录标识
if(card_type==0)
i=sam_iso(buf);
else
i=id_iso(buf);
if(i!=0)
{
if(card_type==SAM_CARD)
return (SAM_COMM_FAIL);
else if(card_type==USER_CARD)
return (USR_COMM_FAIL);
else
return (CHK_COMM_FAIL);
}
i=buf[1]; // 长度
//send_char(i);
// if(testbuf[0]==0xaa)send_str(1,&i);
//
//send_str(2,&buf[len+3]);
//2005.8.9
if(buf[i+3]!=0x90 || buf[i+4]!=0|| i!=len)
//if(buf[len+3]!=0x90 || buf[len+4]!=0)
{
//send_str(2,&buf[len+3]);
if(card_type==SAM_CARD)return (SAM_READ_FAIL);
else if(card_type==USER_CARD) return (USR_READ_FAIL);
else {if(buf[i+3]==0x6a && buf[i+4]==0x83)return FILE_OVER; else return (CHK_READ_FAIL);}
}
memcpy(content,&buf[3],len);
return 0;
}
/*---------------------------------------------------------------------------
说 明:从CPU卡取一串随机数,可以是税控卡.用户卡.稽查卡
参 数:which_card:==0,税控卡;==1,用户卡,==2 稽查卡
len:欲取出的随即数的字节数(有效值:4-10)
content:如果函数调用成功,则为返回的随机数
返回值: ==0,成功;否则失败
作 者:
----------------------------------------------------------------------------*/
uchar get_random(uchar which_card, uchar len, uchar *content)
{
uchar xdata buf[32];
uchar xdata i;
if(which_card > 2 || len > 10 ||len < 4) // 对入口参数的合法性检查
return (PARAM_FAIL);
buf[0]=0x60;
buf[1]=6;
buf[2]=ISO_READ;
buf[3]=0x00; // CLA
buf[4]=0x84; // INS
buf[5]=0x00; // P1
buf[6]=0x00; // P2
buf[7]=len;
if(which_card==SAM_CARD)
i=sam_iso(buf);
else
i=id_iso(buf);
if(i!=0)
{
if(which_card==SAM_CARD)
return (SAM_COMM_FAIL);
else if(which_card==USER_CARD)
return (USR_COMM_FAIL);
else
return (CHK_COMM_FAIL);
}
if(buf[len+3]!=0x90 || buf[len+4]!=0x00 )//|| buf[1]!=len)
{
if(which_card==SAM_CARD)
return (SAM_READ_FAIL);
else if(which_card==USER_CARD)
return (USR_READ_FAIL);
else
return (CHK_READ_FAIL);
}
memcpy(content, &buf[3], len);
return 0;
}
/*--------------------------------------------------------------------------
说 明: 读写国标操作系统的二进制文件 调用之前需要先选择文件
入口参数: which_card: SAM_CARD ---税控卡
USER_CARD ---用户卡
CHECK_CARD ---稽查卡
mode: 0--读,1--写
start_point: 读写开始点范围[0,0xFFFF]
读写偏移位置应小于0x7FFF,
len : 读写长度[0,890](注:此项参数做了穷尽测试)
uchar *content --写文件内容首地址
注意:*content所指数组应大于等于len
出口参数: uchar *content --读文件内容首地址
返 回 值: 0,正确;非0,错误
错 误 码
说 明:
0e1H --超时错
0e2H --接收数据时奇偶校验错
0e3H --发送数据时奇偶校验错
0e4H --非CPU卡
0e5H --ATR数据长度错
0e6H --ATR数据校验错
0e7H --ISO命令方式字节错,ISO_MODE!=0xDA/ISO_READ
0e8H --CPU卡应答字节错
0e9H --卡类型错
作 者:
--------------------------------------------------------------------------*/
uchar RW_bin(uchar which_card, uchar mode,uint start_point, uint length, uchar *content)
{
uchar xdata error;
uchar xdata len_t;
uint xdata i;
uchar xdata count; // uint
uchar xdata buf_t[200];
//TOGGLE_WD();
error=0;
while(1)
{
///////对入口参数的合法性检查
if((which_card>2)||(start_point&0x8000)||(!length)||(length>890)||(mode>1))
{
error = PARAM_FAIL;
break;
}
//******=对文件读或写操作******=
count = length/CPU_OS_LEN; //一次读写CPU的最大字节数 78
if(length%CPU_OS_LEN)count++;
len_t = 0;
if(mode==0)//读文件
{
i=0;
do
{
// TOGGLE_WD();
buf_t[0]=COMMAND_HEAD; //0x60,卡通讯命令的头
buf_t[1]= 6; //长度
buf_t[2]=ISO_READ; //ISO_MODE ISO_READ 0xDB读命令
buf_t[3]=0; // CLA
buf_t[4]=0xB0; // INS
buf_t[5]=((start_point+i*CPU_OS_LEN)>>8)&0xff; // startpoint high
buf_t[6]=(start_point+i*CPU_OS_LEN)&0xff; // startpoint low
length -= len_t;
if(length <= CPU_OS_LEN)len_t = length;//由CPU卡操作系统确定
else len_t = CPU_OS_LEN;
buf_t[7]=len_t; // 一次读取数据的长度 /
if(which_card==SAM_CARD)
error = sam_iso(buf_t);
else
error = id_iso(buf_t);
//send_str(len_t+2,buf_t);
if(error)
switch(which_card)
{
case SAM_CARD:
return(SAM_COMM_FAIL);
case USER_CARD:
return(USR_COMM_FAIL);
case CHK_CARD:
return(CHK_COMM_FAIL);
}
//send_str(2,&buf_t[3+len_t]);
if(buf_t[3+len_t]!=0x90||buf_t[4+len_t]!=0x0) // 判断执行是否成功
{
switch(which_card)
{
case SAM_CARD:
return(SAM_READ_FAIL);
case USER_CARD:
return(USR_READ_FAIL);
case CHK_CARD:
return(CHK_READ_FAIL);
}
}
memcpy(&content[i*CPU_OS_LEN],&buf_t[3],len_t);// 读出内容放入 content *
i++;
}while((len_t<length)&&(i<count));
if(error)break;
}// end of read mode==0
else //写文件
{
i=0;
do
{
length -= len_t;
if(length <= CPU_OS_LEN)len_t = length;// 由CPU卡操作系统确定
else len_t = CPU_OS_LEN;
buf_t[0]=COMMAND_HEAD;
buf_t[1]= 6+len_t;
buf_t[2]=ISO_WRITE;
buf_t[3]=0; //CLA
buf_t[4]=0xD6; // INS
buf_t[5]=((start_point+CPU_OS_LEN*i)>>8)&0xff;// startpoint high
buf_t[6]=(start_point+CPU_OS_LEN*i)&0xff; // startpoint low
buf_t[7]=len_t; // Lc为要写的长度
memcpy(&buf_t[8],&content[CPU_OS_LEN*i],len_t);
if(which_card==SAM_CARD)
error = sam_iso(buf_t);
else
error = id_iso(buf_t);
if(error)
switch(which_card)
{
case SAM_CARD:
return(SAM_COMM_FAIL);
case USER_CARD:
return(USR_COMM_FAIL);
case CHK_CARD:
return(CHK_COMM_FAIL);
}
if(((which_card==USER_CARD)||(which_card==CHK_CARD))
&&((buf_t[3]==0x6a)&&((buf_t[4]==0x83)||(buf_t[4]==0x84))||((buf_t[3]==0x67)&&(buf_t[4]==0x00)))
) return FILE_OVER;
//send_str(2,&buf_t[3]);
if(buf_t[3]!=0x90||buf_t[4]!=0x00)
{
switch(which_card)
{
case SAM_CARD:
return(SAM_WRITE_FAIL);
case USER_CARD:
return(USR_WRITE_FAIL);
case CHK_CARD:
return(CHK_WRITE_FAIL);
}
}
i++;
}while((len_t<length)&&(i<count));
if(error)break;
}//end of write mode==1
//文件读或写成功 //
error = 0;
break;
}// end while(1) **
return error;
}
/*---------------------------------------------------------------
说 明:改写定长记录文件,须先选择文件
参 数:which_card: 卡类型选择 ==0 税控卡 ==1 用户卡 ==3 稽查卡
which_rec: 记录标识
len: 需要写入的明文长度
data_buf: 数据
返 值:==0,成功;==其他,失败
作 者:
-----------------------------------------------------------------*/
uchar WriteRec(uchar which_card, uchar which_rec, uchar len, uchar *data_buf)
{
uchar xdata buf[300];
uchar xdata i;
buf[0]=0x60;
buf[1]=len+6;
buf[2]=ISO_WRITE;
buf[3]=0x00;
buf[4]=0xDC;
buf[5]=which_rec;
buf[6]=0x04;
buf[7]=len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -