📄 tda8007.c
字号:
// Write 5 byte command header
for (index = 0;index < 4;)
writeByte(buffer[index++]);
writeLastByte(buffer[index++]);//index=5?
while (1)
{
// Get procedure byte
retval = readByte();
if (retval < 0)
{
return retval;
}
val = retval;
#if DEBUG > 2
printf("proc byte: %02bx\n",val);
#endif
if ((val & 0xFE) == INS)//shield the B0
{
// ACK, send/receive all remaining bytes
if (index < length)//if length > 5
{
#if DEBUG > 2
printf("write %d bytes\n",length-index);
#endif
for (;index < (length-1);index++)
writeByte(buffer[index]);
if (index < length)
writeLastByte(buffer[index++]);
// NOTE: Does not support VPP state change
}
else
{
#if DEBUG > 2
printf("read bytes\n");
#endif
// 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:
#if DEBUG > 1
printf("Mode T=%bd\n",TMode[currentSlot]);
#endif
return dssc_sendAPDUT0(buffer,length,rbuffer);
break;
case 1:
#if DEBUG > 1
printf("Mode T=%bd\n",TMode[currentSlot]);
#endif
return dssc_sendAPDUT1(buffer,length,rbuffer);
break;
default:
#if DEBUG > 0
printf("Invalid mode T=%bd\n",TMode[currentSlot]);
#endif
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)
if ( DEBUG > 2 )
printf("Waiting for Clock to switch\n");
do
{
val = dssc_readregister(MSR);
}
while (!(val & MSR_CLKSW_MASK));
#endif
if ( DEBUG > 2)
printf("Preparing to Apply Power1\n");
// 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);
if ( DEBUG > 2)
printf("Preparing to Apply Power1\n");
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))
{
#if DEBUG > 0
printf("Power problem detected %02bx\n",val);
#endif
dssc_powerdown();
return ERR_POWERUP_INTERRUPTED;
}
val = dssc_readregister(PCR);
if ( DEBUG > 2 )
printf(".");
}
while (!(val & PCR_START_MASK));
#if DEBUG > 1
printf("Power is on\n");
#endif
//return 1;
// Call common getATR routine
return dssc_ATRsequence(mode);
}
int16_t dssc_ATRsequence(uint8_t mode)
{
uint8_t val;
uint8_t USRval;
uint8_t index;
uint8_t etucount = 0;
int16_t i;
uint8_t historicalBytes;
uint8_t expectedCharacters;
uint8_t interfaceIteration = 1;
uint8_t done = 0;
uint8_t check;
// Default to T=0 mode
uint8_t T = 0;
uint8_t curByte;
clearATRStruct(&lastATR[currentSlot]);
NAD[currentSlot] = 0;
// Reset the UART
val = dssc_readregister(CSR);
dssc_writeregister(CSR,val & ~CSR_nRIU_MASK);
// Remove UART reset
val = dssc_readregister(CSR);
dssc_writeregister(CSR,val | CSR_nRIU_MASK);
// Set FIFO to 1 byte
dssc_writeregister(FCR,0x00);
// Set divisor
dssc_writeregister(PDR,12);
// Set prescaler
dssc_writeregister(UCR2,0x00);
// Enable auto convention
val = dssc_readregister(UCR2);
dssc_writeregister(UCR2,val & ~UCR2_nAUTOCONV_MASK);
// Set SS bit
dssc_writeregister(UCR1,UCR1_SS_MASK);
// Wait 40000 to 45000 cycles to release reset
dssc_writeregister(TOC,0x00);
dssc_writeregister(TOR3,0x00);
dssc_writeregister(TOR2,0x6C);
dssc_writeregister(TOR1,0x00);
dssc_writeregister(TOC,0x61);
do
{
/*
for (i=0;i<10000;i++)
{}
putchar('*');
*/
val = dssc_readregister(USR);
}
while (!(val & USR_TOL3_MASK));
#if DEBUG > 2
printf("Set up counters for reset\n");
#endif
if (mode == POWERUP_ISO)
{
// Wait up to 40000 cycles for ATR to start
dssc_writeregister(TOC,0x00);
dssc_writeregister(TOR3,0x00);
dssc_writeregister(TOR2,0x78);
dssc_writeregister(TOR1,0x00);
dssc_writeregister(TOC,0x61);
}
else // power up EMV
{
// Wait up to 40000 cycles for ATR to start and 19200 etu counter after first byte
dssc_writeregister(TOC,0x00);
dssc_writeregister(TOR3,0x00);
dssc_writeregister(TOR2,0x78);
dssc_writeregister(TOR1,0xC0);
dssc_writeregister(TOC,0x65);
}
#if DEBUG > 1
printf("Release reset\n");
#endif
// Release reset
val = dssc_readregister(PCR);
dssc_writeregister(PCR,val | PCR_RSTIN_MASK);
while (1)
{
#if DEBUG > 2
printf(".");
#endif
val = dssc_readregister(MSR);
// If we see the first character come in, break.
if (val & MSR_TBE_RBF_MASK)
break;
val = dssc_readregister(USR);
if (val & (USR_PE_MASK|USR_FER_MASK|USR_OVR_MASK|USR_EA_MASK))
{
#if DEBUG > 0
printf("ATR error: USR=%02bx\n", val);
#endif
dssc_powerdown();
return ERR_POWERUP_ATR_INVALID;
}
if (val & USR_TOL3_MASK)
{
dssc_powerdown();
#if DEBUG > 0
printf("No ATR within timeout\n");
#endif
return ERR_POWERUP_ATR_TIMEOUT;
}
}
if (mode == POWERUP_ISO)
{
// Set up timer for 9600 etu between characters in ATR
dssc_writeregister(TOC,0x00);
dssc_writeregister(TOR3,0x25);
dssc_writeregister(TOR2,0x80);
dssc_writeregister(TOR1,0x00);
// Start timer
dssc_writeregister(TOC,0x61);
}
else // mode is EMV
{
// Set up timer for 9600 etu between characters in ATR, and
// maximum of 19200 etu for whole ATR
dssc_writeregister(TOC,0x05);
dssc_writeregister(TOR3,0x25);
dssc_writeregister(TOR2,0x80);
dssc_writeregister(TOR1,0xC0);
// Start timer
dssc_writeregister(TOC,0x65);
}
#if DEBUG > 1
printf("Getting ATR\n");
#endif
index = 0;
while (!done)
{
// Read UART status
USRval = dssc_readregister(USR);
{
// If receive buffer full
if (USRval & USR_TBE_RBF_MASK)
{
// Read and store ATR byte
val = dssc_readregister(URR);
curByte = val;
workingBuffer[index++] = val;
if (index == 1)
{
lastATR[currentSlot].TS = curByte;
#if DEBUG > 3
printf("TS: %02bx\n",curByte);
#endif
if ((curByte != 0x3f) && (curByte != 0x3b))
{
#if DEBUG > 0
printf("Invalid TS: %02bx\n",curByte);
#endif
dssc_powerdown();
return ERR_POWERUP_ATR_INVALID;
}
check = 0;
}
else
check ^= curByte;
if (index == 2)
{
historicalBytes = curByte & 0x0F;
expectedCharacters = curByte & 0xF0;
lastATR[currentSlot].T0 = curByte;
#if DEBUG > 3
printf("TO: %02bx\n",curByte);
#endif
}
if (index > 2)
{
switch(expectedCharacters)
{
case 0x00:
// Historical characters
historicalBytes--;
#if DEBUG > 3
printf("hb: %02bx [%c] -%bd\n",curByte,curByte,historicalBytes);
#endif
lastATR[currentSlot].Historical[lastATR[currentSlot].HistoricalLength++] = curByte;
if (historicalBytes == 0)
{
if (T==0)
{
done = 1;
}
else
expectedCharacters = 0x01; // Go to checksum state
}
break;
case 0x01:
// TCK case
#if DEBUG > 3
printf("TCK: %02bx\n",curByte);
#endif
lastATR[currentSlot].TCK = curByte;
done = 1;
break;
case 0x10:
case 0x30:
case 0x50:
case 0x70:
case 0x90:
case 0xB0:
case 0xD0:
case 0xF0:
// TA case
expectedCharacters &= 0xE0;
#if DEBUG > 3
printf("Got TA%bd %02bx\n",interfaceIteration,curByte);
#endif
lastATR[currentSlot].TA[interfaceIteration] = curByte;
break;
case 0x20:
case 0x60:
case 0xA0:
case 0xE0:
// TB case
expectedCharacters &= 0xD0;
#if DEBUG > 3
printf("Got TB%bd %02bx\n",interfaceIteration,curByte);
#endif
lastATR[currentSlot].TB[interfaceIteration] = curByte;
break;
case 0x40:
case 0xC0:
// TC case
expectedCharacters &= 0xB0;
#if DEBUG > 3
printf("Got TC%bd %02bx\n",interfaceIteration,curByte);
#endif
lastATR[currentSlot].TC[interfaceIteration] = curByte;
break;
case 0x80:
// TD case
expectedCharacters=(curByte&0xF0);
// Handle zero historical characters
if ((expectedCharacters == 0x00) && (historicalBytes == 0))
{
if (T==0)
{
done = 1;
}
else
expectedCharacters = 0x01;
}
#if DEBUG > 3
printf("Got TD%bd %02bx\n",interfaceIteration,curByte);
#endif
lastATR[currentSlot].TD[interfaceIteration] = curByte;
// If we get TD1, we have the first protocol selection
if ((interfaceIteration==1))
{
T=curByte & 0x0F;
#if DEBUG > 3
printf("T=%bd\n",T);
#endif
}
else
{
// Changing protocols is only valid under ISO (not allowed in EMV)
if (mode == POWERUP_ISO)
{
if ((curByte & 0x0F) != T)
{
T=curByte & 0x0F;
#if DEBUG > 3
printf("New T=%bd\n",T);
#endif
}
}
else
return ERR_POWERUP_ATR_INVALID; // You cannot change T protocol under EMV
}
interfaceIteration++;
break;
default:
#if DEBUG > 0
printf("Bad expected chars %02bx\n",expectedCharacters);
#endif
dssc_powerdown();
return ERR_POWERUP_ATR_INVALID;
break;
}
}
if (mode == POWERUP_ISO)
{
// Reset timer for 9600 etu between characters in ATR
dssc_writeregister(TOC,0x00);
dssc_writeregister(TOR3,0x25);
dssc_writeregister(TOR2,0x80);
dssc_writeregister(TOR1,0x00);
// Start timer
dssc_writeregister(TOC,0x61);
}
else // mode is EMV
{
// Set up timer for 9600 etu between characters in ATR
// Don't modify TOR1 as it is in auto-reload mode.
dssc_writeregister(TOC,0x05);
dssc_writeregister(TOR3,0x25);
dssc_writeregister(TOR2,0x80);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -