?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 32

?prevdifflink? - Blame - ?getfile?

/********************************************************************
 FileName:              SClib.c
 Dependencies:  See INCLUDES section
 Processor:             PIC18, PIC24 Microcontrollers
 Hardware:              This demo is natively intended to be used on Exp 16, LPC
                                & HPC Exp board. This demo can be modified for use on other hardware
                                platforms.
 Complier:      Microchip C18 (for PIC18), C30 (for PIC24)
 Company:               Microchip Technology, Inc.

 Software License Agreement:

 The software supplied herewith by Microchip Technology Incorporated
 (the “Company”) for its PIC® Microcontroller is intended and
 supplied to you, the Company’s customer, for use solely and
 exclusively on Microchip PIC Microcontroller products. The
 software is owned by the Company and/or its supplier, and is
 protected under applicable copyright laws. All rights are reserved.
 Any use in violation of the foregoing restrictions may subject the
 user to criminal sanctions under applicable laws, as well as to
 civil liability for the breach of the terms and conditions of this
 license.

 THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
 WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
 TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
 IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.

********************************************************************
 File Description:

 Change History:
  Rev   Description
  ----  -----------------------------------------
  1.0   Initial release
  1.01  Cleaned up unnecessary variables,supported T=1 protocol
        and improvments in T=0 functions following the coding standards
********************************************************************/

#include <string.h>
#include "./Smart Card/SClib.h"
#include "sc_config.h"

#if defined(__PIC24F__)
        #include "./Smart Card/SCpic24.h"
#elif defined(__PIC32MX__)
        #include "./Smart Card/SCpic32.h"
#else
        #ifdef __18CXX
        #include "./Smart Card/SCpic18.h"
        #else
        #error "Only PIC18 and PIC24F currently supported by SmartCard Library"
        #endif
#endif

#define MAX_ATR_LEN                     (BYTE)33

BYTE scCardATR[MAX_ATR_LEN];
BYTE scATRLength = 0;

BYTE scTA1, scTA2, scTA3;
BYTE scTB1, scTB2, scTB3;
BYTE scTC1, scTC2, scTC3;
BYTE scTD1, scTD2, scTD3;

BYTE* scATR_HistoryBuffer = NULL;
BYTE  scATR_HistoryLength = 0;

typedef enum
{
        UNKNOWN,
        ATR_ON
} SC_STATUS;

SC_STATUS gCardState = UNKNOWN;
SC_ERROR scLastError = SC_ERR_NONE;

// Work Wait time for T=0 Protocol in units of etu's
unsigned long cgtETU;
unsigned long cgt;
unsigned long t0WWTetu;
unsigned long t0WWT;    
BOOL delayLapsedFlag = FALSE;

static void SC_WaitTime(void);
static void SC_Delay(unsigned int instructionCount);

#ifdef SC_PROTO_T1

        #define R_BLOCK_IDENTIFIER              (BYTE)0x80
        #define S_BLOCK_IDENTIFIER              (BYTE)0xC0
        #define M_BIT_SET                               (BYTE)0x20
        #define M_BIT_CLR                               (BYTE)0xDF
        #define S_BIT_SET                               (BYTE)0x40
        #define S_BIT_CLR                               (BYTE)0xBF
        #define S_BIT_POSITION                  (BYTE)0x40

        unsigned long t1BWT;
        unsigned long t1CWT;
        unsigned long t1BGT;
        unsigned int t1BWTetu;
        unsigned int t1CWTetu;

        BYTE t1BGTetu = 22;

        BYTE edcType = SC_LRC_TYPE_EDC;
        BYTE maxSegmentLength = 0x20;
        BOOL txSbit = TRUE;

        static WORD SC_UpdateCRC(BYTE data,WORD crc);
        static void SC_UpdateEDC(BYTE data,WORD *edc);
        static void SC_SendT1Block(BYTE nad,BYTE pcb,WORD length,BYTE *buffer);
        static BOOL SC_ReceiveT1Block(BYTE *rxNAD,BYTE *rxPCB,BYTE *rxLength,BYTE *buffer,unsigned long blockWaitTime);

#endif

// CLA set to '00' = no command chaining, 
//                   no secure messaging, 
//                                       basic logical channel.

/*******************************************************************************
  Function:
    void SC_Initialize(void)
        
  Description:
    This function initializes the smart card library

  Precondition:
    None

  Parameters:
    None

  Return Values:
    None
        
  Remarks:
    None
  *****************************************************************************/
void SC_Initialize()
{
        //Initialize the low level driver
        SCdrv_InitUART();
}

/*******************************************************************************
  Function:
        BOOL SC_CardPresent(void)       
  
  Description:
    This macro checks if card is inserted in the socket

  Precondition:
    SC_Initialize() is called

  Parameters:
    None

  Return Values:
    TRUE if Card is inserted, otherwise return FALSE
        
  Remarks:
    None
  *****************************************************************************/
BOOL SC_CardPresent()
{
        return SCdrv_CardPresent();
}       

/*******************************************************************************
  Function:
        BOOL SC_PowerOnATR(void)        
  
  Description:
    This function performs the power on sequence of the SmartCard and 
        interprets the Answer-to-Reset data received from the card.

  Precondition:
    SC_Initialize() is called, and card is present

  Parameters:
    None

  Return Values:
    TRUE if Answer to Reset (ATR) was successfuly received and processed
        
  Remarks:
    None
  *****************************************************************************/
BOOL SC_PowerOnATR()
{
        unsigned long atrDelayCnt;

        if( !SCdrv_CardPresent() )  //check card present
        {
                gCardState = UNKNOWN;
                return FALSE;
        }
                
        SCdrv_SetSwitchCardReset(0);  //make sure card in reset
        memset( scCardATR, 0xFF, sizeof scCardATR );
        WaitMilliSec(2);        

        #ifdef ENABLE_SC_POWER_THROUGH_PORT_PIN
                SCdrv_SetSwitchCardPower(1);    //Turn on power
        #endif

        scATR_HistoryLength = 0;
        scATR_HistoryBuffer = NULL;
        gCardState = UNKNOWN;
        scLastError = SC_ERR_NONE;
        scATRLength = 0;
//      t0WWT = (9600UL * (FCY/baudRate))/4;
        atrDelayCnt = 40000UL * (FCY/scReferenceClock);
        WaitMilliSec(2);

        SCdrv_EnableUART();

        WaitMilliSec(2);

        //Start the clock
        SCdrv_EnableClock();    

        // Wait for atleast 400 Clock Cycles after applying reference clock to card.
        WaitMilliSec(2);

        SCdrv_SetSwitchCardReset(1);  //Release card reset line. set to high state

        while(1)  ///////////////// Read Answer to RESET
        {
                if( SCdrv_GetRxData( &scCardATR[scATRLength], atrDelayCnt ) ) //wait for data byte from CARD
                {
                        scATRLength++;

                        if( scATRLength == MAX_ATR_LEN )
                                break;
//                      else
//                              atrDelayCnt = t0WWT;
                }
                else
                        break;  //no data
        }
                
        //decode the ATR values
        if( scATRLength >= 3 ) //min TS, T0 and setup byte
        {
                BYTE T0 = scCardATR[1]; 
                BYTE atrIdx = 2;
                
                //Extract Interface bytes TAx TBx TCx and TDx from ATR
                
                scTA1 = scTB1 = scTC1 = scTD1 = 0;
                scTA2 = scTB2 = scTC2 = scTD2 = 0;
                scTA3 = scTB3 = scTC3 = scTD3 = 0;
                
                // Read the global interface bytes
                
                if( T0 & 0x10 )
                        scTA1 = scCardATR[atrIdx++];
                        
                if( T0 & 0x20 )
                        scTB1 = scCardATR[atrIdx++];
                        
                if( T0 & 0x40 )
                        scTC1 = scCardATR[atrIdx++];

                if( T0 & 0x80 )
                        scTD1 = scCardATR[atrIdx++];
                        
                //read the next set of interface bytes if present
                if( scTD1 & 0xF0 )
                {
                        if( scTD1 & 0x10 )
                                scTA2 = scCardATR[atrIdx++];
                                
                        if( scTD1 & 0x20 )
                                scTB2 = scCardATR[atrIdx++];
                                
                        if( scTD1 & 0x40 )
                                scTC2 = scCardATR[atrIdx++];
                                
                        if( scTD1 & 0x80 )
                                scTD2 = scCardATR[atrIdx++];
                                
                        if( scTD2 & 0xF0 )
                        {
                                if( scTD2 & 0x10 )
                                {
                                        scTA3 = scCardATR[atrIdx++];
                                        
                                        if ((scTA3 < 0x10) || (scTA3 == 0xFF))
                                        {
                                                SC_Shutdown();
                                                scLastError = SC_ERR_ATR_DATA;
                                                return FALSE;
                                        }

                                        #ifdef SC_PROTO_T1
                                                maxSegmentLength = scTA3;
                                        #endif
                                }

                                if( scTD2 & 0x20 )
                                        scTB3 = scCardATR[atrIdx++];
                                        
                                if( scTD2 & 0x40 )
                                {
                                        scTC3 = scCardATR[atrIdx++];

                                        #ifdef SC_PROTO_T1
                                                edcType = (scTC3 & 0x01) ? SC_CRC_TYPE_EDC : SC_LRC_TYPE_EDC;
                                        #endif
                                }

                                if( scTD2 & 0x80 )
                                        scTD3 = scCardATR[atrIdx++];                            
                        }
                }
                
                scATR_HistoryLength = T0 & 0x0F;
                scATR_HistoryBuffer = (scATR_HistoryLength)?(&scCardATR[atrIdx]):NULL;
                SC_WaitTime();
                gCardState = ATR_ON;
                SCdrv_EnableDelayTimerIntr();
                return TRUE;
        }
        else
        {
                // Not a Valid ATR Reponse
                scLastError = SC_ERR_BAR_OR_NO_ATR_RESPONSE;
                gCardState = UNKNOWN;   
                SC_Shutdown();  
                return FALSE;
        }       
}


/*******************************************************************************
  Function:
        BOOL SC_DoPPS(void)     
  
  Description:
    This function does the PPS to the card & configures the baud rate of the PIC UART
        to match with Answer-to-Reset data from smartcard.

  Precondition:
    SC_PowerOnATR was success

  Parameters:
    None

  Return Values:
    TRUE if Baud rate is supported by the PIC
        
  Remarks:
    This function is called when SC_PowerOnATR() returns TRUE.  If the Baud 
        rate configration file inside the card is changed, these function should 
        be called again for the new baud to take effect.
  *****************************************************************************/
BOOL SC_DoPPS()
{
        if( !SCdrv_CardPresent() || gCardState != ATR_ON )
                return FALSE;
        
        if( scTA1 == 0x11 )     //card using 9600 baud.  no need to configure
                return TRUE;

        // If TA2 is absent & TD1 is present
        if(!(scTD1 & 0x10) && (scCardATR[1] & 0x80) && !(scTD1 & 0x0F)) 
        {
                SCdrv_SendTxData( 0xFF ); // PPSS Byte = 0xFF always

                if(scCardATR[1] & 0x10)
                {       
                        SCdrv_SendTxData( 0x10 );       // PPS0
                        SCdrv_SendTxData( scTA1 );      // PPS1
                        SCdrv_SendTxData( 0xFF ^ 0x10 ^ scTA1 );        // PCK

                        SCdrv_SetBRG( scTA1 );  //tell the driver to configure baud rate
                        SC_WaitTime();
                }
                else
                {
                        SCdrv_SendTxData( 0x00 );       // PPS0
                        SCdrv_SendTxData( 0xFF);        // PCK
                }               
        }

        return TRUE;
}

/*******************************************************************************
  Function:
    int SC_GetCardState(void)
        
  Description:
    This function returns the current state of SmartCard

  Precondition:
    SC_Initialize is called.

  Parameters:
    None

  Return Values:
    SC_STATE_CARD_NOT_PRESENT:          No Card Detected
    SC_STATE_CARD_ACTIVE:                       Card is powered and ATR received
    SC_STATE_CARD_INACTIVE:                     Card present but not powered
        
  Remarks:
    None
  *****************************************************************************/
int SC_GetCardState()
{
        if( !SCdrv_CardPresent() )
                return SC_STATE_CARD_NOT_PRESENT;
        else if( gCardState == ATR_ON )
                return SC_STATE_CARD_ACTIVE;
        else
                return SC_STATE_CARD_INACTIVE;
}               

/*******************************************************************************
  Function:
    void SC_Shutdown(void)
        
  Description:
    This function Performs the Power Down sequence of the SmartCard

  Precondition:
    SC_Initialize is called.

  Parameters:
    None

  Return Values:
    None
        
  Remarks:
    None
  *****************************************************************************/
void SC_Shutdown()
{
        SCdrv_SetSwitchCardReset(0);    //bring reset line low
        WaitMilliSec(1);
        SCdrv_CloseUART();                      //shut down UART and remove any pullups
        #ifdef ENABLE_SC_POWER_THROUGH_PORT_PIN
                SCdrv_SetSwitchCardPower(0);   //Turn Off Card Power
        #endif
        gCardState = UNKNOWN;
}


/*******************************************************************************
  Function:
    void SC_WaitTime(void)
        
  Description:
    This function calculates the work wait time for T=0 Protocol

  Precondition:
    SC_PowerOnATR is called.

  Parameters:
    None

  Return Values:
    None
        
  Remarks:
    This function is planned to calculate CWT & BWT for T=1 protocol in future.
  *****************************************************************************/
static void SC_WaitTime(void)
{
        float factorD = 1;
        unsigned int factorF = 372;
        BYTE ta1Code,tb2Code,index;
        unsigned int tempVariable;
        
        ta1Code = scTA1 & 0x0F;
        
        // Calculate Factor 'D' from TA1 value
        switch(ta1Code)
        {
                case 0x00:
                case 0x07:
                case 0x01:
                                        break;

                case 0x02:
                                        factorD = 2;
                                        break;

                case 0x03:
                                        factorD = 4;
                                        break;

                case 0x04:
                                        factorD = 8;
                                        break;

                case 0x05:
                                        factorD = 16;
                                        break;

                case 0x06:
                                        factorD = 32;
                                        break;

                case 0x08:
                                        factorD = 12;
                                        break;

                case 0x09:
                                        factorD = 20;
                                        break;

                case 0x0A:
                                        factorD = 0.5;
                                        break;

                case 0x0B:
                                        factorD = 0.25;
                                        break;

                case 0x0C:
                                        factorD = 0.125;
                                        break;

                case 0x0D:
                                        factorD = 0.0625;
                                        break;

                case 0x0E:
                                        factorD = 0.03125;
                                        break;

                case 0x0F:
                                        factorD = 0.015625;
                                        break;
        }

        ta1Code = (scTA1 & 0xF0) >> 4;
                
        // Calculate Factor 'F' from TA1 value
        switch(ta1Code)
        {
                case 0x00:
                case 0x07:
                case 0x08:
                case 0x0E:
                case 0x0F:
                                        break;
        
                case 0x01:
                                        factorF = 372;
                                        break;
        
                case 0x02:
                                        factorF = 558;
                                        break;

                case 0x03:
                                        factorF = 744;
                                        break;
        
                case 0x04:
                                        factorF = 1116;
                                        break;
        
                case 0x05:
                                        factorF = 1488;
                                        break;
        
                case 0x06:
                                        factorF = 1860;
                                        break;
        
                case 0x09:
                                        factorF = 512;
                                        break;
        
                case 0x0A:
                                        factorF = 768;
                                        break;
        
                case 0x0B:
                                        factorF = 1024;
                                        break;
        
                case 0x0C:
                                        factorF = 1536;
                                        break;
        
                case 0x0D:
                                        factorF = 2048;
                                        break;  
        }
        
        // Check whether T=0 or T=1 protocol ?
        switch(scTD1 & 0x0F)
        {
                case 1 :
                                        // Calculate Character Guard Time in ETU's for T=1 Protocol
                                        if(scTC1 == 0xFF)
                                        {
                                                cgtETU = 11;
                                        }
                                        else
                                        {
                                                cgtETU = 12 + (unsigned long)((float)((float)(factorF * scTC1)/factorD)/scReferenceClock);
                                        }
                
                                        #ifdef SC_PROTO_T1

                                                if(scTD1 & 0x20)
                                                {
                                                        tb2Code = scTB2 & 0x0F;
                                                
                                                        tempVariable = 1;
                                                        for(index = 0;index < tb2Code;index++)
                                                                tempVariable = tempVariable * 2;
                                                        // Calculate Character Wait Time in ETU's for T=1 Protocol as set in the card
                                                        t1CWTetu = 11 + tempVariable;
                                                
                                                        tb2Code = (scTB2 & 0xF0) >> 4;

                                                        tempVariable = 1;
                                                        for(index = 0;index < tb2Code;index++)
                                                                tempVariable = tempVariable * 2;

                                                        // Calculate Block Wait Time in ETU's for T=1 Protocol as set in the card                                               
                                                        t1BWTetu = 11 + (unsigned int)((unsigned long)(tempVariable * 35712UL)/(scReferenceClock/10));
                                                }
                                                else
                                                {
                                                        for(index = 0;index < SC_CWI;index++)
                                                                tempVariable = tempVariable * 2;

                                                        // Calculate default value of Character Wait Time in ETU's for T=1 Protocol.
                                                        t1CWTetu = 11 + tempVariable;

                                                        tempVariable = 1;
                                                        for(index = 0;index < SC_BWI;index++)
                                                                tempVariable = tempVariable * 2;

                                                        // Calculate default value of Block Wait Time in ETU's for T=1 Protocol.
                                                        t1BWTetu = 11 + (unsigned int)((unsigned long)(tempVariable * 357120UL)/scReferenceClock);
                                                }

                                        #endif

                                        break;
                case 0 :
                default :
                                        // If scTC2 is transmitted by the card then calculate work wait time
                                        // or else use default value
                                        if(scTD1 & 0x40)
                                        {
                                                t0WWTetu = (unsigned long)(scTC2 * factorD * 960);
                                        }
                                        else
                                        {
                                                t0WWTetu = (unsigned long)(SC_WI * factorD * 960);
                                        }

                                        // Calculate Character Guard Time in ETU's for T=1 Protocol             
                                        if(scTC1 == 0xFF)
                                        {
                                                cgtETU = 12;
                                        }
                                        else
                                        {
                                                cgtETU = 12 + (unsigned long)((float)((float)(factorF * scTC1)/factorD)/scReferenceClock);
                                        }
        
                                        break;
        }

        if(t0WWTetu <= cgtETU)
                t0WWTetu = cgtETU * 100;        

        // Calculate Character Guard Time in number of Instruction Counts for T=0/T=1 Protocol          
        cgt = cgtETU * (FCY/baudRate);

        // Calculate Work Wait Time in number of Instruction Counts for T=0 Protocol
        t0WWT = t0WWTetu * (FCY/baudRate);

        #ifdef SC_PROTO_T1

                if(t1BWTetu <= t1BGTetu)
                        t1BWTetu = t1BGTetu * 100;

                if(t1CWTetu <= cgtETU)
                        t1CWTetu = cgtETU * 100;

                // Calculate Character Wait Time in number of Instruction Counts for T=1 Protocol
                t1CWT = t1CWTetu * (FCY/baudRate);

                // Calculate Block Guard Time in number of Instruction Counts for T=1 Protocol
                t1BGT = t1BGTetu * (FCY/baudRate);

                // Calculate Block Wait Time in number of Instruction Counts for T=1 Protocol
                t1BWT = t1BWTetu * (FCY/baudRate);

        #endif
}       

/*******************************************************************************
  Function:
        BOOL SC_TransactT0(SC_APDU_COMMAND* apduCommand, SC_APDU_RESPONSE* apduResponse, BYTE* apduDataBuffer)  
  
  Description:
    This function Sends the ISO 7816-4 compaliant APDU commands to the card.  
        It also receive the expected response from the card as defined by the 
        command data.

  Precondition:
    SC_DoPPS was success

  Parameters:
    SC_APDU_COMMAND* apduCommand        - Pointer to APDU Command Structure 
        SC_APDU_RESPONSE* pResp - Pointer to APDU Response structure
                        BYTE* pResp - Pointer to the Command/Response Data buffer

  Return Values:
    TRUE if transaction was success, and followed the ISO 7816-4 protocol. 
        
  Remarks:
    In the APDU command structure, the LC field defines the number of bytes to 
        transmit from the APDUdat array.  This array can hold max 256 bytes, which 
        can be redefined by the user.  The LE field in APDU command defines the number
        of bytes to receive from the card.  This array can hold max 256 bytes, which 
        can be redefined by the user.
        
  *****************************************************************************/
BOOL SC_TransactT0(SC_APDU_COMMAND* apduCommand, SC_APDU_RESPONSE* apduResponse, BYTE* apduDataBuffer)
{
        BYTE* apduCommandBuffer;
        BYTE index,lc = apduCommand->LC,le = apduCommand->LE,ins = apduCommand->INS;
        BYTE rx_char;
        BYTE lcLength = 0,leLength = 0;
        unsigned int txDelay;

        // Return False if there is no Card inserted in the Slot
        if( !SCdrv_CardPresent() || gCardState != ATR_ON )
        {
                scLastError = SC_ERR_CARD_NOT_PRESENT;
                return FALSE;   
        }       

        // Clear APDU Response data if present before getting the new one's
        memset( apduResponse, 0, sizeof(SC_APDU_RESPONSE) );
        
        apduCommandBuffer = (BYTE*)apduCommand;
        
        txDelay = cgt/8;

        //Send the Command Bytes: CLA INS P1 P2
        for( index = 0; index < 4; index++ )
        {
                SCdrv_SendTxData( apduCommandBuffer[index] );
                SC_Delay(txDelay);
        }       
        
        //Now transmit LE or LC field if non zero
        if( lc )
                SCdrv_SendTxData( lc );
        else if( le )
                SCdrv_SendTxData( le );

        while (1)
        {
        // Get Procedure byte
                if(!SCdrv_GetRxData( &rx_char, t0WWT ) ) //wait for data byte from CARD
                {
                        scLastError = SC_ERR_CARD_NO_RESPONSE;
                        return FALSE;   //no response received
                }       

                // Process Procedure Byte
                if (rx_char == 0x60)
                {
                        // Do Nothing
        }
        else if (((rx_char & 0xF0) == 0x60) || ((rx_char & 0xF0) == 0x90))
        {
                // SW1, get SW2
                        apduResponse->SW1 = rx_char; //save SW1
                        
                        //now receive SW2
                        if( SCdrv_GetRxData( &rx_char, t0WWT ) ) //wait for data byte from CARD
                                apduResponse->SW2 = rx_char;
                        else
                        {
                                scLastError = SC_ERR_CARD_NO_RESPONSE;
                                return FALSE;   //no response received
                        }

                        break;
        }
                else if(rx_char == ins)
                {
                        // Send all remaining bytes
                        if( lcLength < lc)              //transmit app data if any
                        {
                                WaitMicroSec( 700 );    //cannot send the message data right away after the initial response
                                SC_Delay(txDelay);

                                for(;lcLength < lc; lcLength++ )
                                {       
                                        SCdrv_SendTxData( apduDataBuffer[lcLength] );
                                        SC_Delay(txDelay);
                                }
                        }
                        else
                        {
                                // Recive all remaining bytes
                                for(;leLength < le; leLength++ )
                                {       
                                        if( SCdrv_GetRxData( &rx_char, t0WWT ) ) //wait for data byte from CARD
                                                apduDataBuffer[leLength] = rx_char;     
                                        else
                                        {
                                                scLastError = SC_ERR_CARD_NO_RESPONSE;
                                                return FALSE;   //no response received
                                        }
                                }               
                        }
                }
                else if(rx_char == ~ins)
                {
                // ACK, send one byte if remaining
                if (lcLength < lc)
                {
                                SC_Delay(txDelay);

                                SCdrv_SendTxData( apduDataBuffer[lcLength++] );
                }
                else
                {
                                //wait for data byte from CARD or timeout
                                if( SCdrv_GetRxData( &rx_char, t0WWT ) ) 
                                        apduDataBuffer[leLength++] = rx_char;   
                                else
                                {
                                        scLastError = SC_ERR_CARD_NO_RESPONSE;
                                        return FALSE;   //no response received
                                }
                        }
                }
                else
                {
                        // Do Nothing
                }
        }

        // Store the number of recieved data bytes other than the
        // status codes to make the life of Smart Card Reader easier
        apduResponse->RXDATALEN = leLength;

        return TRUE;
}

/*******************************************************************************
  Function:
    void SC_Delay(void)
        
  Description:
    This function waits for delay to get completed

  Precondition:
    None.

  Parameters:
    unsigned int instructionCount - Number of instruction counts to be waited

  Return Values:
    None
        
  Remarks:
    None.
  *****************************************************************************/
static void SC_Delay(unsigned int instructionCount)
{
        // Set the Timer Count as per the delay needed
        SCdrv_SetDelayTimerCnt(0xFFFF - instructionCount);

        // Enable the delay timer
        SCdrv_EnableDelayTimer();

        // Wait until the delay is elapsed
        while(!delayLapsedFlag);

        // Clear the delay flag
        delayLapsedFlag = FALSE;
}

#ifdef SC_PROTO_T1

/*******************************************************************************
  Function:
    void SC_UpdateCRC(void)
        
  Description:
    This function calculates 16 bit CRC for T=1 Protocol

  Precondition:
    Initial value of crc should be 0xFFFF.

  Parameters:
    BYTE data - Data that has to be used to update CRC.
        WORD *edc - Pointer to CRC

  Return Values:
    WORD - updated CRC
        
  Remarks:
    CRC 16 - X^16 + X^12 + X^5 + 1

  *****************************************************************************/
static WORD SC_UpdateCRC(BYTE data,WORD crc)
{
        WORD index;
        WORD tempData = (WORD)data << 8;

        // Update the CRC & return it Back
        for (index = 0;index < 8;index++)
        {
                if ((crc ^ tempData) & 0x8000)
                {
                        crc <<= 1;
                        crc ^= (WORD)0x1021; // X^12 + X^5 + 1
                }
                else
                {
                        crc <<= 1;
                }
                
                tempData <<= 1;
        }
        
        return(crc);
}

/*******************************************************************************
  Function:
    void SC_UpdateEDC(BYTE data,WORD *edc)
        
  Description:
    This function updates Error Data Check value depending on the EDC type
    for T=1 Protocol

  Precondition:
    None.

  Parameters:
    BYTE data - Data that has to be used to update EDC.
        WORD *edc - Pointer to EDC

  Return Values:
    None
        
  Remarks:
    None

*****************************************************************************/
static void SC_UpdateEDC(BYTE data,WORD *edc)
{
        // Store the updated LRC/CRC in the EDC
        if (edcType == SC_CRC_TYPE_EDC) // type = CRC
        {
                *edc = SC_UpdateCRC(data,*edc);
        }
        else // type = LRC
        {
                *edc = *edc ^ data;
        }
}

/*******************************************************************************
  Function:
    static void SC_SendT1Block(BYTE nad,BYTE pcb,WORD length,BYTE *buffer)
        
  Description:
    This function transmits a T=1 formatted block

  Precondition:
    Complete ATR...

  Parameters:
    BYTE nad - NAD to be transmitted to the card
    BYTE pcb - PCB to be transmitted to the card
    WORD length - Length of I-Field transmitted to the card
    BYTE *buffer - Pointer to data that is to be transmitted to the card

  Return Values:
    None
        
  Remarks:
    None

*****************************************************************************/
static void SC_SendT1Block(BYTE nad,BYTE pcb,WORD length,BYTE *buffer)
{
        WORD index;
        WORD edc;

        // Choose the initial value of edc depending upon LRC or CRC
        if (edcType == SC_CRC_TYPE_EDC)
        {
                edc = 0xFFFF;
        }
        else
        {
                edc = 0;
        }
        // Update the edc for Node Address Data Byte
        SC_UpdateEDC(nad,&edc);

        // Update the edc for Protocol Control Byte
        SC_UpdateEDC(pcb,&edc);

        // Update the edc for length of tx Bytes
        SC_UpdateEDC(length,&edc);

        // Update the edc for the data to be transmitted
        for (index=0;index<length;index++)
        {
                SC_UpdateEDC(buffer[index],&edc);
        }

        // Transmit Node Address
        SCdrv_SendTxData(nad);

        // Transmit Protocol Control Byte       
        SCdrv_SendTxData(pcb);

        // Transmit length of Data Byte 
        SCdrv_SendTxData(length);

        // Transmit Data Bytes
        for (index=0;index<length;index++)
        {
                SCdrv_SendTxData(buffer[index]);
        }

        // Transmit EDC
        if (edcType == SC_LRC_TYPE_EDC)
        {
                SCdrv_SendTxData(edc);
        }
        else
        {
                SCdrv_SendTxData(edc);
            SCdrv_SendTxData(edc>>8);
        }
}

/*******************************************************************************
  Function:
    void SC_ReceiveT1Block(void)
        
  Description:
    This function receives a T=1 formatted block

  Precondition:
    Transmit a block before expecting the response...

  Parameters:
    BYTE *rxNAD - Pointer to NAD recieved from the card
    BYTE *rxPCB - Pointer to PCB recieved from the card
    BYTE *rxLength - Pointer to Length of I-Field recieved from the card
    BYTE *buffer - Pointer to data recieved from the card
        unsigned long blockWaitTime - value of Block Wait Time

  Return Values:
    TRUE if block recieve is successful, and follows the ISO 7816-4 protocol. 
        
  Remarks:
    None
*****************************************************************************/
static BOOL SC_ReceiveT1Block(BYTE *rxNAD,BYTE *rxPCB,BYTE *rxLength,BYTE *buffer,unsigned long blockWaitTime)
{
        WORD edc;
        WORD index;
        BYTE expectedLength;

        // Get NAD
        if(!SCdrv_GetRxData( rxNAD, blockWaitTime ))
        {
                scLastError = SC_ERR_CARD_NO_RESPONSE;
                return FALSE;
        }

        // Get PCB
        if(!SCdrv_GetRxData( rxPCB, t1CWT ))
        {
                scLastError = SC_ERR_CARD_NO_RESPONSE;
                return FALSE;
        }

        // Get Length   
        if(!SCdrv_GetRxData( rxLength, t1CWT ))
        {
                scLastError = SC_ERR_CARD_NO_RESPONSE;
                return FALSE;
        }

        // Add one to the expected length for LRC
        expectedLength = *rxLength + 1;

        // Add additional byte to the length if using CRC
        if (edcType == SC_CRC_TYPE_EDC)
                expectedLength++;

        // Get all the data bytes plus EDC (1 or 2 bytes at end)
        for (index = 0;index < expectedLength;)
        {
                if(!SCdrv_GetRxData( buffer + index, t1CWT ))
                {
                        scLastError = SC_ERR_CARD_NO_RESPONSE;
                        return FALSE;
                }
                
                ++index;
        }

        // Check the LRC or CRC Error
        if (edcType == SC_LRC_TYPE_EDC)
        {
                edc = 0;
                SC_UpdateEDC(*rxNAD,&edc);
                SC_UpdateEDC(*rxPCB,&edc);
                SC_UpdateEDC(*rxLength,&edc);
                for (index = 0;index < expectedLength;)
                {
                        SC_UpdateEDC(*(buffer + index),&edc);
                        ++index;
                }

                if (edc != 0)
                {
                        scLastError = SC_ERR_RECEIVE_LRC;
                        return FALSE;
                }
        }
        else // EDC is CRC
        {
                edc = 0xFFFF;
                SC_UpdateEDC(*rxNAD,&edc);
                SC_UpdateEDC(*rxPCB,&edc);
                SC_UpdateEDC(*rxLength,&edc);
                for (index = 0;index < (expectedLength-2);)
                {
                        SC_UpdateEDC(*(buffer + index),&edc);
                        ++index;
                }

                if (((edc >> 8) != buffer[expectedLength-2]) || ((edc & 0xFF) != buffer[expectedLength-1]))
            {
                        scLastError = SC_ERR_RECEIVE_CRC;
                        return FALSE;
                }
        }
        
        // Return TRUE if there is no LRC or CRC error & data bytes are recieved sucessfully
        return TRUE;
}

/*******************************************************************************
  Function:
        BOOL SC_TransactT1(SC_T1_PROLOGUE_FIELD* pfield,BYTE* iField,SC_APDU_RESPONSE* apduResponse)
  
  Description:
    This function Sends the ISO 7816-4 compaliant APDU commands to the card.  
        It also receive the expected response from the card as defined by the 
        command data.

  Precondition:
    SC_DoPPS was success

  Parameters:
    SC_T1_PROLOGUE_FIELD* pfield - Pointer to Prologue Field 
        BYTE* iField - Pointer to the Information Field of Tx/Rx Data
        SC_APDU_RESPONSE* apduResponse - Pointer to APDU Response structure

  Return Values:
    TRUE if transaction was success, and followed the ISO 7816-4 protocol. 
        
  Remarks:      
  *****************************************************************************/

BOOL SC_TransactT1(SC_T1_PROLOGUE_FIELD* pfield,BYTE* iField,SC_APDU_RESPONSE* apduResponse)
{
        BOOL    t1TransactCompleted = FALSE,txMbit = FALSE;
        BOOL    rxMbit = FALSE,rxSbit = FALSE,transmitNextSegment = TRUE;
        BYTE    txLength,txPCB = pfield->PCB,rxNAD,rxPCB,rxLEN;
        BYTE    initialLength = pfield->LENGTH,iFieldLength,retryR = 0,retrySync = 0;
        WORD    rxLength = 0;
        BYTE*   rxField = iField;
        BYTE*   txField = iField;
        BYTE*   initialField = iField;
        unsigned long currT1BWT = t1BWT;
        T1BLOCK_TYPE t1TxBlockType,currentT1RxBlockType;

        iFieldLength = initialLength;

        // Determine which type of block is to be transmitted to the card
        if((txPCB & 0x80) == 0x00)
        {
                // I-Block
                t1TxBlockType = I_BLOCK;

                if(txSbit)
                {
                        txPCB = txPCB & S_BIT_CLR;
                        txSbit = FALSE;
                }
                else
                {
                        txPCB = txPCB | S_BIT_SET;
                        txSbit = TRUE;
                }
        }
        else if((txPCB & 0xC0) == 0xC0)
        {
                // S-Block
                t1TxBlockType = S_BLOCK;
        }
        else if((txPCB & 0xC0) == 0x80)
        {
                // R-Block
                t1TxBlockType = R_BLOCK;
        }
        else
        {
                // INVALID BLOCK
                return FALSE;
        }

        // Go to appropriate case depending upon the type of block
        switch(t1TxBlockType)
        {
                case    I_BLOCK:
                                                        // Continue Untill Transaction is Passed or Failed...
                                                        while (!t1TransactCompleted)
                                                        {
                                                                // If Next segment has to be transmitted to the card
                                                                if(transmitNextSegment)
                                                                {
                                                                        txMbit = FALSE;

                                                                        if(iFieldLength > maxSegmentLength)
                                                                        {
                                                                                txLength = maxSegmentLength;
                                                                                txMbit = TRUE;
                                                                                txPCB = txPCB | M_BIT_SET;
                                                                        }
                                                                        else
                                                                        {
                                                                                txLength = iFieldLength;
                                                                                txPCB = txPCB & M_BIT_CLR;
                                                                        }
                                                                
                                                                        txField = iField;
                                                                }

                                                                // Send block with chaining mode, current sequence number, and maximum length.
                                                                SC_SendT1Block(pfield->NAD,txPCB,txLength,txField);
                                                                
                                                                // Recieve the Block
                                                                if(SC_ReceiveT1Block(&rxNAD,&rxPCB,&rxLEN,rxField,currT1BWT))
                                                                {
                                                                        // Determine the type of Block recieved from the card
                                                                        if((rxPCB & 0x80) == 0x00)
                                                                        {
                                                                                // I-Block
                                                                                currentT1RxBlockType = I_BLOCK;
                                                                                
                                                                                if((rxPCB & 0x20) == 0x20)
                                                                                        rxMbit = TRUE;
                                                                                else
                                                                                        rxMbit = FALSE;

                                                                                if((rxPCB & 0x40) == 0x40)
                                                                                        rxSbit = TRUE;
                                                                                else
                                                                                        rxSbit = FALSE;

                                                                                transmitNextSegment = FALSE;
                                                                                
                                                                                retryR = 0;retrySync = 0;
                                                                        }
                                                                        else if((rxPCB & 0xC0) == 0xC0)
                                                                        {
                                                                                // S-Block
                                                                                currentT1RxBlockType = S_BLOCK;
                                                                                
                                                                                retryR = 0;retrySync = 0;
                                                                        }
                                                                        else if((rxPCB & 0xC0) == 0x80)
                                                                        {
                                                                                // R-Block
                                                                                currentT1RxBlockType = R_BLOCK;
                                                                                
                                                                                retryR = 0;retrySync = 0;
                                                                        }
                                                                        else
                                                                        {
                                                                                // INVALID BLOCK
                                                                                currentT1RxBlockType = INVALID_BLOCK;
                                                                        }
                                                                }
                                                                else
                                                                {
                                                                        // No Block Recieved or Error Block Recieved
                                                                        currentT1RxBlockType = INVALID_BLOCK;
                                                                }
                                                
                                                                currT1BWT = t1BWT;
                                                                
                                                                switch(currentT1RxBlockType)
                                                                {
                                                                        case    I_BLOCK :
                                                                                                                rxField = rxField + (BYTE)rxLEN;
                                                                                                                rxLength = rxLength + rxLEN;
                                                                                                                iFieldLength = 0;

                                                                                                                // If More Bit is set by the card,
                                                                                                                // send the apprpriate R Block
                                                                                                                if(rxMbit)
                                                                                                                {
                                                                                                                        // Transmit R(N) - Expected Seq
                                                                                                                        txLength = 0x00;
                                                                                                                        
                                                                                                                        if(rxSbit)
                                                                                                                                txPCB = 0x80;
                                                                                                                        else
                                                                                                                                txPCB = 0x90;
                                                                                                                }
                                                                                                                else
                                                                                                                {
                                                                                                                        // No More Bit set from the card,
                                                                                                                        // Data is recieved with the status
                                                                                                                        // codes...we are done
                                                                                                                        if(rxLEN)
                                                                                                                        {
                                                                                                                                // We are Done here
                                                                                                                                t1TransactCompleted = TRUE;
                                                                                                                                if(rxLength >= 2)
                                                                                                                                {
                                                                                                                                        apduResponse->RXDATALEN = rxLength - 2;
                                                                                                                                        apduResponse->SW1 = *(initialField + (BYTE)rxLength - (BYTE)2);
                                                                                                                                        apduResponse->SW2 = *(initialField + (BYTE)rxLength - (BYTE)1);
                                                                                                                                }
                                                                                                                        }
                                                                                                                        else
                                                                                                                        {
                                                                                                                                // Transmit Forced Acknowledge I Block
                                                                                                                                txLength = 0x00;
                                                                                                                        
                                                                                                                                if(txSbit)
                                                                                                                                {
                                                                                                                                        txPCB = 0x00;
                                                                                                                                        txSbit = FALSE;
                                                                                                                                }
                                                                                                                                else
                                                                                                                                {
                                                                                                                                        txPCB = 0x40;
                                                                                                                                        txSbit = TRUE;
                                                                                                                                }
                                                                                                                        }
                                                                                                                }

                                                                                                                break;

                                                                        case    S_BLOCK :
                                                                                                                // Card can only send Resync Response...
                                                                                                                // Card cant do Resync request
                                                                                                                if((rxPCB & 0x3F) == 0x20) // Resync Response from the card
                                                                                                                {
                                                                                                                        txSbit = FALSE;
                                                                                                                        return FALSE;
                                                                                                                }
                                                                                                                else if((rxPCB & 0x3F) == 0x01) // Request IFS Change
                                                                                                                {
                                                                                                                        txPCB = SC_IFS_RESPONSE;
                                                                                                                        txLength = 1;
                                                                                                                        txField = rxField;
                                                                                                                        maxSegmentLength = *rxField;
                                                                                                                        transmitNextSegment = FALSE;
                                                                                                                        continue;
                                                                                                                }
                                                                                                                else if((rxPCB & 0x3F) == 0x03) // Request Wait time Extension
                                                                                                                {
                                                                                                                        currT1BWT = t1BWT * *rxField;
                                                                                                                        txPCB = SC_WAIT_TIME_EXT_RESPONSE;
                                                                                                                        txLength = 1;
                                                                                                                        txField = rxField;
                                                                                                                        transmitNextSegment = FALSE;
                                                                                                                        continue;
                                                                                                                }
                                                                                                                else if((rxPCB & 0x3F) == 0x24) // VPP Error Response
                                                                                                                {
                                                                                                                        scLastError = SC_CARD_VPP_ERR;
                                                                                                                        return FALSE;
                                                                                                                }
                                                                                                                else if((rxPCB & 0x3F) == 0x02) // Abort Request
                                                                                                                {
                                                                                                                        txPCB = SC_ABORT_RESPONSE;
                                                                                                                        txLength = 0;
                                                                                                                        if(txMbit)
                                                                                                                        {
                                                                                                                                // Do this so that there is last byte transmission to terminate
                                                                                                                                // the communication
                                                                                                                                iFieldLength = maxSegmentLength + 1;
                                                                                                                        }
                                                                                                                        transmitNextSegment = FALSE;
                                                                                                                        continue;
                                                                                                                }
                                                                                                                break;

                                                                        case    R_BLOCK :
                                                                                                                // If Recieved Seq Number not equal
                                                                                                                // to transmitted Seq Number
                                                                                                                if(rxSbit != txSbit)
                                                                                                                {
                                                                                                                        // If More Bit is set by the reader
                                                                                                                        if(txMbit)
                                                                                                                        {
                                                                                                                                // Transmission of previous segment was
                                                                                                                                // succesful. Transmit next segment.
                                                                                                                                transmitNextSegment = TRUE;

                                                                                                                                iFieldLength = iFieldLength - maxSegmentLength;
                                                                                                                                iField = iField + maxSegmentLength;

                                                                                                                                // Toggle the Sequence Bit
                                                                                                                                if(txSbit)
                                                                                                                                {
                                                                                                                                        txPCB = 0x00;
                                                                                                                                        txSbit = FALSE;
                                                                                                                                }
                                                                                                                                else
                                                                                                                                {
                                                                                                                                        txPCB = 0x40;
                                                                                                                                        txSbit = TRUE;
                                                                                                                                }
                                                                                                                        }
                                                                                                                        else
                                                                                                                        {
                                                                                                                                // There was some error, trasmit previous
                                                                                                                                // block
                                                                                                                                transmitNextSegment = FALSE;
                                                                                                                        }
                                                                                                                }
                                                                                                                else
                                                                                                                {
                                                                                                                        // Retransmit the I-Block
                                                                                                                        transmitNextSegment = TRUE;
                                                                                                                }
                                                                                                                
                                                                                                                break;

                                                                        case    INVALID_BLOCK   :
                                                                                                                                // If 1st Block transaction itself 
                                                                                                                                // is failing transmit R(0)
                                                                                                                                if(initialLength == iFieldLength)
                                                                                                                                {
                                                                                                                                        txPCB = 0x82;
                                                                                                                                        txLength = 0x00;
                                                                                                                                        transmitNextSegment = FALSE;
                                                                                                                                        retryR++;
                                                                                                                                        retrySync = 0;

                                                                                                                                        // Try transmitting R(0) twice
                                                                                                                                        // before telling error to the
                                                                                                                                        // Smart Card Reader
                                                                                                                                        if(retryR > 2)
                                                                                                                                        {
                                                                                                                                                scLastError = SC_ERR_CARD_NO_RESPONSE;
                                                                                                                                                return FALSE;
                                                                                                                                        }
                                                                                                                                }
                                                                                                                                else
                                                                                                                                {
                                                                                                                                        transmitNextSegment = FALSE;
                                                                                                                                        
                                                                                                                                        // Try transmitting R(0) twice                                                                                                                                                                                                                                                  // Try transmitting R(0) twice
                                                                                                                                        // before transmitting ReSync
                                                                                                                                        // Request to the card
                                                                                                                                        if(retryR < 2)
                                                                                                                                        {
                                                                                                                                                if(rxMbit)
                                                                                                                                                        txPCB = 0x82;
                                                                                                                                                else
                                                                                                                                                        txPCB = 0x92;
                                                                                                                                        
                                                                                                                                                txLength = 0x00;
                                                                                                                                                retryR++;
                                                                                                                                                retrySync = 0;
                                                                                                                                        }
                                                                                                                                        else
                                                                                                                                        {
                                                                                                                                                txPCB = 0xC0;
                                                                                                                                                txLength = 0x00;
                                                                                                                                                retrySync++;
                                                                                                                                                                                                                                                                                // Try transmitting R(0) twice                                                                                                                                                                                                                                                  // Try transmitting R(0) twice
                                                                                                                                                // Try transmitting Resync Request
                                                                                                                                                // thrice before telling error to the
                                                                                                                                                // Smart Card Reader
                                                                                                                                                if(retrySync > 3)
                                                                                                                                                {
                                                                                                                                                        scLastError = SC_ERR_CARD_NO_RESPONSE;
                                                                                                                                                        return FALSE;
                                                                                                                                                }
                                                                                                                                        }
                                                                                                                                }
                                                                                                                                
                                                                                                                                continue;
                                                                                                                                
                                                                                                                                break;
                                                                }
                                                        }       
                                                        
                                                        break;

                case    S_BLOCK:
                                                        // Continue Untill Transaction is Passed or Failed...
                                                        while (!t1TransactCompleted)
                                                        {
                                                                // Send mode, current sequence number, and maximum length.
                                                                SC_SendT1Block(pfield->NAD,txPCB,0,txField);

                                                                // Recieve the Block    
                                                                if(SC_ReceiveT1Block(&rxNAD,&rxPCB,&rxLEN,rxField,currT1BWT))
                                                                {
                                                                        // Determine the type of Block recieved from the card
                                                                        if((rxPCB & 0x80) == 0x00)
                                                                        {
                                                                                // I-Block
                                                                                currentT1RxBlockType = I_BLOCK;
                                                                        }
                                                                        else if((rxPCB & 0xC0) == 0xC0)
                                                                        {
                                                                                // S-Block
                                                                                currentT1RxBlockType = S_BLOCK;
                                                                        }
                                                                        else if((rxPCB & 0xC0) == 0x80)
                                                                        {
                                                                                // R-Block
                                                                                currentT1RxBlockType = R_BLOCK;
                                                                        }
                                                                        else
                                                                        {
                                                                                // INVALID BLOCK
                                                                                currentT1RxBlockType = INVALID_BLOCK;
                                                                        }
                                                                }
                                                                else
                                                                {
                                                                        // No Block Recieved or Error Block Recieved
                                                                        currentT1RxBlockType = INVALID_BLOCK;
                                                                }
                                                                
                                                                switch(currentT1RxBlockType)
                                                                {
                                                                        case    S_BLOCK :
                                                                                                                // If Acknowledged properly, return 
                                                                                                                // TRUE to the card reader
                                                                                                                if((txPCB | 0x20) == rxPCB)
                                                                                                                {
                                                                                                                        t1TransactCompleted = TRUE;
                                                                                                                        break;
                                                                                                                }
                                                                                                                else
                                                                                                                {
                                                                                                                        // Try transmitting thrice before
                                                                                                                        // telling error to the Smart
                                                                                                                        // Card Reader
                                                                                                                        retrySync++;
                                                                                                                        
                                                                                                                        if(retrySync > 3)
                                                                                                                        {
                                                                                                                                scLastError = SC_ERR_CARD_NO_RESPONSE;
                                                                                                                                return FALSE;
                                                                                                                        }

                                                                                                                        continue;
                                                                                                                }
                                                                                                                break;
                                                                        case    R_BLOCK :
                                                                        case    I_BLOCK :
                                                                        case    INVALID_BLOCK   :
                                                                                                                        // Try transmitting thrice before
                                                                                                                        // telling error to the Smart
                                                                                                                        // Card Reader
                                                                                                                        retrySync++;
                                                                                                                        if(retrySync > 3)
                                                                                                                        {
                                                                                                                                scLastError = SC_ERR_CARD_NO_RESPONSE;
                                                                                                                                return FALSE;
                                                                                                                        }
                                                                                                                        continue;
                                                                                                                        break;
                                                                }
                                                        }
                                                        break;
                
                case    R_BLOCK:
                default:
                                                break;
        }

        // Return TRUE if everything is fine
        return TRUE;
}

#endif

{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3