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

📄 ds8007.c.bak

📁 DS8007 双智能卡读卡DEMO源代码。
💻 BAK
📖 第 1 页 / 共 2 页
字号:
/*---------------------------------------------------------------------------
 *  Copyright (C) 2004 Dallas Semiconductor Corporation, All Rights Reserved.
 * 
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 * 
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 * 
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *  IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
 *  OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *  OTHER DEALINGS IN THE SOFTWARE.
 * 
 *  Except as contained in this notice, the name of Dallas Semiconductor
 *  shall not be used except as stated in the Dallas Semiconductor
 *  Branding Policy.
 * ---------------------------------------------------------------------------
 */
/** 
 * \file ds8007.c
 * \brief Interface library for Dallas Semiconductor's DS8007 smartcard interface chip
 *
 * This library contains routines required to communicate with smartcards
 * via an DS8007 while conforming to:
 * ISO 7816
 * EMV 4.1
 *
 */

#include <stdio.h>
#include <string.h>

#include <reg5000.h>
#include <absacc.h>
#include "DS8007.h"

#define DEBUG 1

void clearATRstruct(struct ATR*);
int16_t dssc_ATRsequence(uint8_t);

uint8_t workingBuffer[512];
uint8_t ATRLength[CARD_SLOTS];
struct ATR lastATR[CARD_SLOTS];
uint8_t TMode[CARD_SLOTS];		// T=0 or T=1
uint32_t WWT[CARD_SLOTS];		// Work wait time
uint32_t CWT[CARD_SLOTS];		// Character wait time
uint32_t BWT[CARD_SLOTS];		// Block wait time
uint8_t EDCtype[CARD_SLOTS];
uint8_t NAD[CARD_SLOTS];		// Node address byte to use when communicating in T=1
uint8_t IFSC[CARD_SLOTS];		// Maximum segment length when sending to card in T=1
uint8_t currentSlot = 0;

/*
Dump formatted contents of ATR struct
*/
void dumpATRStruct(struct ATR myatr)
{
	int i;
  	printf("ATR\n");
	printf("TS: %02bx\n",(uint8_t)myatr.TS);
  	printf("T0: %02bx\n",(uint8_t)myatr.T0);
	for (i = 1;i < 8;i++)
	{
		if (myatr.TA[i] != -1)
			printf("TA%d: %02bx\n",i,(uint8_t)myatr.TA[i]);
		if (myatr.TB[i] != -1)
			printf("TB%d: %02bx\n",i,(uint8_t)myatr.TB[i]);
		if (myatr.TC[i] != -1)
			printf("TC%d: %02bx\n",i,(uint8_t)myatr.TC[i]);
		if (myatr.TD[i] != -1)
			printf("TD%d: %02bx\n",i,(uint8_t)myatr.TD[i]);
	}
	for (i = 0;i < myatr.HistoricalLength;i++)
	{
    	printf("%02bx ",myatr.Historical[i]);
	}
  	printf("\n");
	if (myatr.TCK != -1)
		printf("TCK: %02bx\n",(uint8_t)myatr.TCK);

}

/*
Used to clear the ATR struct before card power up.
*/
void clearATRStruct(struct ATR *myatr)
{
	memset(myatr,0xFF,sizeof(struct ATR));
	myatr->HistoricalLength = 0;
}

/* 
CCITT CRC 16
X^16+X^12+X^5+1
Be sure to use 0xFFFF as initial crc value.
*/
uint16_t update_crc(uint8_t value, uint16_t crc)
{
	int i;

  	uint16_t newval = value << 8;

	for (i = 0;i < 8;i++)
	{
		if ((crc ^ newval) & 0x8000)
		{
			crc <<= 1;
			crc ^= 0x1021;
		}
		else
		{
			crc <<= 1;
		}
		newval <<= 1;
	}
	return crc;
}

/*
Read a byte from the UART or timeout after BWT (T=1), CWT (T=1) or WWT (T=0).
*/
int16_t readByte()
{
	uint8_t val;
	uint32_t timeout;

	while(!(dssc_readregister(MSR) & MSR_TBE_RBF_MASK))
	{
		val = dssc_readregister(USR);
		if (val & USR_PE_MASK)
		{
      		return ERR_RECEIVE_PARITY;
		}
		if (val & (USR_TOL3_MASK|USR_TOL2_MASK|USR_TOL1_MASK))
		{
			return ERR_RECEIVE_TIMEOUT;
		}
	}

	// Read and store byte
	val = dssc_readregister(URR);

	if (TMode[currentSlot] == 0)
		timeout = WWT[currentSlot];  // Use WWT for T=0
	else
		timeout = CWT[currentSlot];  // Use CWT for T=1

	// Set up timer for 24 bit timer, start immediately
	dssc_writeregister(TOC,0x00);
	dssc_writeregister(TOR3,timeout >> 16);
	dssc_writeregister(TOR2,timeout >> 8);
	dssc_writeregister(TOR1,timeout);
	dssc_writeregister(TOC,0x68);

	return val;
}

/*
Write a byte and leave the DS8007 in transmit mode
*/
void writeByte(uint8_t onebyte)
{
	uint8_t val;
	val = dssc_readregister(UCR1);
	// set T bit
	dssc_writeregister(UCR1,val | UCR1_T_R_MASK);
	dssc_writeregister(UTR,onebyte);
	// wait for byte to go out
	while (!(dssc_readregister(USR) & USR_TBE_RBF_MASK));
}

/*
Write a byte and put the DS8007 in receive mode
*/
void writeLastByte(uint8_t onebyte)
{
	uint8_t val;
	uint32_t timeout;

  	if (TMode[currentSlot] == 0)
		timeout = WWT[currentSlot];  // Use WWT for T=0
	else
		timeout = BWT[currentSlot];  // Use BWT for T=1

	// Set up timer for 24 bit timer, edge trigger start
  	dssc_writeregister(TOC,0x00);
	dssc_writeregister(TOR3,timeout >> 16);
	dssc_writeregister(TOR2,timeout >> 8);
	dssc_writeregister(TOR1,timeout);
	dssc_writeregister(TOC,0x7C);

	val = dssc_readregister(UCR1);
	// set LCT and T bit
	dssc_writeregister(UCR1,val | (UCR1_T_R_MASK|UCR1_LCT_MASK));
	dssc_writeregister(UTR,onebyte);
	// wait for byte to go out
	while (!(dssc_readregister(USR) & USR_TBE_RBF_MASK));
}

/*
Generate Error Data Check value depending on EDC type
*/
uint16_t generateEDC(uint8_t type,uint8_t onebyte,uint16_t value)
{
	if (type == EDC_TYPE_LRC)
	{
		return (value ^ onebyte);
	}
	else // type = CRC
	{
		return update_crc(onebyte,value);
	}
}

/*
Send a T=1 formatted block.
Formats T=1 packet from raw input data.  Length must already be
within the requirements of the destination smart card.
*/
void sendBlock(uint8_t NAD,uint8_t PCB,int16_t length,uint8_t *buffer,uint8_t type)
{
	int i;
	uint16_t EDC;

	if (type == EDC_TYPE_LRC)
	{
		EDC = 0;
	}
	else // type = CRC
	{
		EDC = 0xFFFF;
	}

	writeByte(NAD);
	EDC = generateEDC(type,NAD,EDC);
	writeByte(PCB);
	EDC = generateEDC(type,PCB,EDC);
	writeByte(length);
	EDC = generateEDC(type,length,EDC);
	for (i=0;i<length;i++)
	{
		writeByte(buffer[i]);
		EDC = generateEDC(type,buffer[i],EDC);
	}

	if (type == EDC_TYPE_LRC)
	{
		writeLastByte(EDC);
	}
	else // type = CRC
	{
		writeByte(EDC);
	    writeLastByte(EDC>>8);
	}
}

/*
Receive a T=1 formatted block.
This does a raw receive, it does not check sequence numbers.
*/
int16_t receiveBlock(uint8_t *rNAD,uint8_t *rPCB,uint8_t *rLEN,uint8_t *buffer,uint8_t type)
{
	int16_t retval;
	int16_t index = 0;
	uint16_t EDC;
	int16_t i;
	uint8_t expectedLength;

  	// Get NAD, PCB, and Length
	retval = readByte();
	if (retval < 0) return retval;
	*rNAD = retval;
	retval = readByte();
	if (retval < 0) return retval;
	*rPCB = retval;
	retval = readByte();
	if (retval < 0) return retval;
	*rLEN = retval;


	// Add one to length for LRC
	expectedLength = *rLEN+1;
	// Add additional byte if using CRC
	if (type == EDC_TYPE_CRC)
		expectedLength++;

	// Get all data bytes plus EDC (1 or 2 bytes at end)
	for (i = 0;i < expectedLength;i++)
	{
		retval = readByte();
		if (retval < 0)
		{
			return retval;
		}
		buffer[index++] = retval;
	}

	// Check the LRC or CRC
	if (type == EDC_TYPE_LRC)
	{
		EDC = 0;
		EDC = generateEDC(EDC_TYPE_LRC,*rNAD,EDC);
		EDC = generateEDC(EDC_TYPE_LRC,*rPCB,EDC);
		EDC = generateEDC(EDC_TYPE_LRC,*rLEN,EDC);
		for (i = 0;i < index;i++)
		{
			EDC = generateEDC(EDC_TYPE_LRC,buffer[i],EDC);
		}
		if (EDC != 0)
		{
			return ERR_RECEIVE_LRC;
		}
	}
	else // EDC is CRC
	{
		EDC = 0xFFFF;
		EDC = generateEDC(EDC_TYPE_LRC,*rNAD,EDC);
		EDC = generateEDC(EDC_TYPE_LRC,*rPCB,EDC);
		EDC = generateEDC(EDC_TYPE_LRC,*rLEN,EDC);
		for (i = 0;i < (index-2);i++)
		{
			EDC = generateEDC(EDC_TYPE_CRC,buffer[i],EDC);
		}
    
		if (((EDC >> 8) != buffer[index-2]) ||
			((EDC & 0xFF) != buffer[index-1]))
	    {
			return ERR_RECEIVE_CRC;
		}
	}
	return *rLEN;
}

/*
Send an S block for setting IFSD (card terminal buffer size)
*/
int16_t dssc_sendsblockIFSD(uint8_t IFSD)
{
	uint8_t buffer[1];
	uint8_t rNAD,rPCB,rLEN;
	uint8_t rbuffer[100];

	buffer[0] = IFSD;
	sendBlock(0,0xC1,1,buffer,EDCtype[currentSlot]);
	receiveBlock(&rNAD,&rPCB,&rLEN,rbuffer,EDCtype[currentSlot]);

	// If we do not get a confirmation response, fail.
	if ((rPCB == 0xE1) && (rLEN == 1) && (rbuffer[0] == IFSD))
		return 0;
	else
		return ERR_SETIFSD_FAILURE;
}

/*
Set Node address info for this card
*/
void dssc_setNAD(uint8_t value)
{
	NAD[currentSlot] = value;
}

/*
Send a message using T=1 protocol
*/
int16_t dssc_sendAPDUT1(uint8_t *buffer,int16_t length,uint8_t *rbuffer)
{
	int16_t maxSegLength = IFSC[currentSlot];  // Set by ATR (TA3), or default to 0x20
	int16_t retval;
	uint8_t sequenceNumber = 0;
	uint8_t rNAD,rPCB,rLEN;
	uint8_t tempbuffer[512];

	while (length > maxSegLength)
	{
		// Send block with chaining mode, current sequence number, and maximum length.
		sendBlock(NAD[currentSlot],sequenceNumber|0x20,maxSegLength,buffer,EDCtype[currentSlot]);
		retval = receiveBlock(&rNAD,&rPCB,&rLEN,tempbuffer,EDCtype[currentSlot]);
		if (retval < 0) return retval;
		// Check for bad sequence number return
		if ((rPCB ^ ((sequenceNumber>>2) ^ 0x10)) != 0x80)
		{
			return ERR_RECEIVE_SEQUENCENUM;
		}
		sequenceNumber ^= 0x40;
		buffer += maxSegLength;
		length -= maxSegLength;
	}

	// Send last (or only) block.  Then, we can wait for the receive side.
	sendBlock(NAD[currentSlot],sequenceNumber,length,buffer,EDCtype[currentSlot]);

	retval = receiveBlock(&rNAD,&rPCB,&rLEN,tempbuffer,EDCtype[currentSlot]);
	if (retval < 0) return retval;

	memcpy(rbuffer,tempbuffer,rLEN);

	return retval;
}

/*
Send a message using T=0 protocol
*/
int16_t dssc_sendAPDUT0(uint8_t *buffer,int16_t length,uint8_t *rbuffer)
{
	int index;
	int16_t rindex = 0;
	uint8_t val;
	uint8_t INS = buffer[1];
	int retval;

	// Write 5 byte command header
	for (index = 0;index < 4;)
		writeByte(buffer[index++]);
	writeLastByte(buffer[index++]);

	while (1)
	{
    	// Get procedure byte
		retval = readByte();
		if (retval < 0)
		{
			return retval;
		}
		val = retval;

		if ((val & 0xFE) == INS)
		{
			// ACK, send/receive all remaining bytes
			if (index < length)
			{
				for (;index < (length-1);index++)
				writeByte(buffer[index]);
				if (index < length)
					writeLastByte(buffer[index++]);
				// NOTE: Does not support VPP state change
			}
			else
			{
				// Read bytes up to Lc/P3 + 2
				rindex = 0;
				while ( (rindex < (buffer[4] + 2)) && ((retval = readByte()) >= 0) )
				{
					rbuffer[rindex++] = retval;
				}
			// return any error.
			if (retval < 0)
				return retval;
			break;
			}
		}
    	else if ((val & 0xFE) == ~INS)
		{
      		if (index < length)
      		{
        		// ACK, send/receive one remaining byte
        		if (index < length)
          			writeLastByte(buffer[index++]);
        		// NOTE: Does not support VPP state change
      		}
      		else
      		{
				// Read one byte or timeout????
        		retval = readByte();
        		if (retval < 0)
        		{
          			// If we get anything other than a timeout, return the error.
          			if (retval != ERR_RECEIVE_TIMEOUT)
            			return retval;
          			break;
        		}
        		else
          		rbuffer[rindex++] = retval;
      		}
    	}
    	else if (val == 0x60)
    	{
      	// NULL
    	}
    	else if (((val & 0xF0) == 0x60) || ((val & 0xF0) == 0x90))
    	{
      		// SW1, get SW2
      		rbuffer[rindex++]=val;
      		val = readByte();
      		if (retval < 0) return retval;
      		rbuffer[rindex++]=val;
      		break;
    	}

	}

  	return rindex;
}

/*
Send a message using T=0 or T=1 protocol
*/
int16_t dssc_sendAPDU(uint8_t *buffer,int16_t length,uint8_t *rbuffer)
{
	switch (TMode[currentSlot])
  	{
    	case 0:
      		return dssc_sendAPDUT0(buffer,length,rbuffer);
      		break;
    	case 1:
      		return dssc_sendAPDUT1(buffer,length,rbuffer);
      		break;
    	default:
      		return ERR_PROTOCOL_UNSUPPORTED;
      		break;
  	}
}

int16_t dssc_warmreset(uint8_t mode)
{
	uint8_t val;

  	// Check for power status
  	val = dssc_readregister(PCR);
  	if (!(val & PCR_START_MASK))
		return ERR_POWERUP_VOLTAGE_INVALID;

	// Apply reset
  	val = dssc_readregister(PCR);
	dssc_writeregister(PCR,val & ~PCR_RSTIN_MASK);

	// Call common getATR routine
	return dssc_ATRsequence(mode);
}

int16_t dssc_powerup(uint8_t mode, uint8_t voltage)
{
	uint8_t val;

	// Compile time setting of operating crystal frequency
#if ((CRYSTAL_FREQUENCY_8007 >= 1000000L) && (CRYSTAL_FREQUENCY_8007 <= 5000000L))
	// Set smartcard clock to 1/1 crystal
  	dssc_writeregister(CCR,0x00);
#elif ((CRYSTAL_FREQUENCY_8007 >= 2000000L) && (CRYSTAL_FREQUENCY_8007 <= 10000000L))
	// Set smartcard clock to 1/2 crystal
	dssc_writeregister(CCR,0x01);
#elif ((CRYSTAL_FREQUENCY_8007 >= 4000000L) && (CRYSTAL_FREQUENCY_8007 <= 20000000L))
	// Set smartcard clock to 1/4 crystal
	dssc_writeregister(CCR,0x02);
#elif ((CRYSTAL_FREQUENCY_8007 >= 8000000L) && (CRYSTAL_FREQUENCY_8007 <= 40000000L))
	// Set smartcard clock to 1/8 crystal
  	dssc_writeregister(CCR,0x03);
#else
	// Set smartcard clock to 1/2 internal oscillator (about 1.44MHz)
  	// NOTE: Can only change CCR.2 when shifting to internal oscillator
	dssc_writeregister(CCR,0x01);
  	dssc_writeregister(CCR,0x05);
	// Wait for internal oscillator to engage (check the MSR.CLKSW bit on page 18)

	do
	{
		val = dssc_readregister(MSR);
	}
	while (!(val & MSR_CLKSW_MASK));
#endif

	// Set the power supply voltage
	val = dssc_readregister(PCR);
	// Clear 1.8V and 3V bits
	dssc_writeregister(PCR,val & ~(PCR_3V_5V_MASK|PCR_1V8_MASK));
	switch(voltage)
	{
	case POWERUP_5V:
		// Do nothing
		break;
    case POWERUP_3V:
		val = dssc_readregister(PCR);
		// Set 3V bit
		dssc_writeregister(PCR,val | PCR_3V_5V_MASK);
		break;
	case POWERUP_1p8V:
		val = dssc_readregister(PCR);
		// Set 1.8V bit
		dssc_writeregister(PCR,val | PCR_1V8_MASK);
		break;
	default:
		return ERR_POWERUP_VOLTAGE_INVALID;
		break;
  	}

	// Apply reset
	val = dssc_readregister(PCR);
  	dssc_writeregister(PCR,val & ~PCR_RSTIN_MASK);

	val = dssc_readregister(HSR);
	do
	{
		// Power the card, RST low, C4 and C8 high
		val = dssc_readregister(PCR);
		dssc_writeregister(PCR,val | (PCR_C8_MASK|PCR_C4_MASK|PCR_START_MASK));
		val = dssc_readregister(HSR);
	    if (val & (HSR_PRTL2_MASK|HSR_PRTL1_MASK|HSR_PRL2_MASK|HSR_PRL1_MASK|HSR_PTL_MASK))
    	{
			dssc_powerdown();
			return ERR_POWERUP_INTERRUPTED;
	    }
		val = dssc_readregister(PCR);

	}
	while (!(val & PCR_START_MASK));

	//return 1;

	// Call common getATR routine
	return dssc_ATRsequence(mode);
}

int16_t dssc_ATRsequence(uint8_t mode)
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -