⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 card_trans.c

📁 税控收款机源码:拼音输入法,LCD,VFD驱动,IC卡驱动,税控国标
💻 C
📖 第 1 页 / 共 2 页
字号:


/*-------------------------------------------------------------
功能:卡的数据传输(命令响应结构)
说明:符合国家标准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 + -