SAMV71 Xplained Ultra Software Package 1.4

iso7816_4.c

Go to the documentation of this file.
00001 /* ----------------------------------------------------------------------------
00002  *         SAM Software Package License 
00003  * ----------------------------------------------------------------------------
00004  * Copyright (c) 2014, Atmel Corporation
00005  *
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright notice,
00012  * this list of conditions and the disclaimer below.
00013  *
00014  * Atmel's name may not be used to endorse or promote products derived from
00015  * this software without specific prior written permission.
00016  *
00017  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
00020  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00022  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00023  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00024  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00025  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00026  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  * ----------------------------------------------------------------------------
00028  */
00029 
00030 /**
00031  * \file
00032  *
00033  * \section Purpose
00034  *
00035  * ISO 7816 driver
00036  *
00037  * \section Usage
00038  *
00039  * Explanation on the usage of the code made available through the header file.
00040  */
00041 
00042 /*------------------------------------------------------------------------------
00043  *         Headers
00044  *----------------------------------------------------------------------------*/
00045 
00046 #include "board.h"
00047 
00048 /*------------------------------------------------------------------------------
00049  *         Definitions
00050  *----------------------------------------------------------------------------*/
00051 /** Case for APDU commands*/
00052 #define CASE1  1
00053 #define CASE2  2
00054 #define CASE3  3
00055 
00056 /** Flip flop for send and receive char */
00057 #define USART_SEND 0
00058 #define USART_RECEIVE  1
00059 
00060 #define USART7816BAUDRATE 9600
00061 /*-----------------------------------------------------------------------------
00062  *          Internal variables
00063  *---------------------------------------------------------------------------*/
00064 /** Variable for state of send and receive from USART */
00065 static uint8_t StateUsartGlobal = USART_RECEIVE;
00066 /** Pin reset master card */
00067 static Pin st_pinIso7816RstMC;
00068 static Usart *UsartIso;
00069 static uint32_t UsartIsoId;
00070 
00071 /*----------------------------------------------------------------------------
00072  *          Internal functions
00073  *----------------------------------------------------------------------------*/
00074 
00075 /**
00076  * Get a character from ISO7816
00077  * \param pCharToReceive Pointer for store the received char
00078  * \return 0: if timeout else status of US_CSR
00079  */
00080 static uint32_t ISO7816_GetChar( uint8_t *pCharToReceive )
00081 {
00082     uint32_t status;
00083     uint32_t timeout=0;
00084 
00085     if( StateUsartGlobal == USART_SEND ) {
00086         while((UsartIso->US_CSR & US_CSR_TXEMPTY) == 0) {}
00087         UsartIso->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
00088         StateUsartGlobal = USART_RECEIVE;
00089     }
00090 
00091     /* Wait USART ready for reception */
00092     while( ((UsartIso->US_CSR & US_CSR_RXRDY) == 0) ) {
00093         if(timeout++ > 12000 * (BOARD_MCK/1000000)) {
00094             TRACE_DEBUG("TimeOut\n\r");
00095             return( 0 );
00096         }
00097     }
00098 
00099     TRACE_DEBUG("T: %u\n\r", timeout);
00100 
00101 
00102     /* At least one complete character has been received and US_RHR has not 
00103     yet been read. */
00104 
00105     /* Get a char */
00106     *pCharToReceive = ((UsartIso->US_RHR) & 0xFF);
00107 
00108     status = (UsartIso->US_CSR&(US_CSR_OVRE | US_CSR_FRAME |
00109                             US_CSR_PARE | US_CSR_TIMEOUT | US_CSR_NACK |
00110                             (1<<10)));
00111 
00112     if (status != 0 ) {
00113         /* TRACE_DEBUG("R:0x%X\n\r", status); */
00114         TRACE_DEBUG("R:0x%X\n\r", UsartIso->US_CSR);
00115         TRACE_DEBUG("Nb:0x%X\n\r", UsartIso->US_NER );
00116         UsartIso->US_CR = US_CR_RSTSTA;
00117     }
00118 
00119     /* Return status */
00120     return( status );
00121 }
00122 
00123 /**
00124  * Send a char to ISO7816
00125  * \param CharToSend char to be send
00126  * \return status of US_CSR
00127  */
00128 static uint32_t ISO7816_SendChar( uint8_t CharToSend )
00129 {
00130     uint32_t status;
00131 
00132     if( StateUsartGlobal == USART_RECEIVE ) {
00133         UsartIso->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
00134         StateUsartGlobal = USART_SEND;
00135     }
00136 
00137     /* Wait USART ready for transmit */
00138     while((UsartIso->US_CSR & US_CSR_TXRDY) == 0)  {}
00139     /* There is no character in the US_THR */
00140 
00141     /* Transmit a char */
00142     UsartIso->US_THR = CharToSend;
00143 
00144     status = (UsartIso->US_CSR & (US_CSR_OVRE | US_CSR_FRAME |
00145                         US_CSR_PARE | US_CSR_TIMEOUT | US_CSR_NACK |
00146                         (1<<10)));
00147 
00148     if (status != 0 ) {
00149         TRACE_DEBUG("E:0x%X\n\r", UsartIso->US_CSR);
00150         TRACE_DEBUG("Nb:0x%X\n\r", UsartIso->US_NER );
00151         UsartIso->US_CR = US_CR_RSTSTA;
00152     }
00153 
00154     /* Return status */
00155     return( status );
00156 }
00157 
00158 
00159 /**
00160  *  Iso 7816 ICC power on
00161  */
00162 static void ISO7816_IccPowerOn( void )
00163 {
00164     /* Set RESET Master Card */
00165     PIO_Set(&st_pinIso7816RstMC);
00166 }
00167 
00168 /*----------------------------------------------------------------------------
00169  *          Exported functions
00170  *----------------------------------------------------------------------------*/
00171 
00172 /**
00173  *  Iso 7816 ICC power off
00174  */
00175 void ISO7816_IccPowerOff( void )
00176 {
00177     /* Clear RESET Master Card */
00178     PIO_Clear(&st_pinIso7816RstMC);
00179 }
00180 
00181 /**
00182  * Transfer Block TPDU T=0
00183  * \param pAPDU    APDU buffer
00184  * \param pMessage Message buffer
00185  * \param wLength  Block length
00186  * \return         Message index
00187  */
00188 uint16_t ISO7816_XfrBlockTPDU_T0(const uint8_t *pAPDU,
00189                                        uint8_t *pMessage,
00190                                        uint16_t wLength )
00191 {
00192     uint16_t NeNc;
00193     uint16_t indexApdu = 4;
00194     uint16_t indexMessage = 0;
00195     uint8_t SW1 = 0;
00196     uint8_t procByte = 0;
00197     uint8_t cmdCase;
00198     uint8_t ins;
00199 
00200     TRACE_DEBUG("pAPDU[0]=0x%X\n\r",pAPDU[0]);
00201     TRACE_DEBUG("pAPDU[1]=0x%X\n\r",pAPDU[1]);
00202     TRACE_DEBUG("pAPDU[2]=0x%X\n\r",pAPDU[2]);
00203     TRACE_DEBUG("pAPDU[3]=0x%X\n\r",pAPDU[3]);
00204     TRACE_DEBUG("pAPDU[4]=0x%X\n\r",pAPDU[4]);
00205     TRACE_DEBUG("wlength=%d\n\r",wLength);
00206 
00207     ISO7816_SendChar( pAPDU[0] ); /* CLA */
00208     ISO7816_SendChar( pAPDU[1] ); /* INS */
00209     ISO7816_SendChar( pAPDU[2] ); /* P1 */
00210     ISO7816_SendChar( pAPDU[3] ); /* P2 */
00211     ISO7816_SendChar( pAPDU[4] ); /* P3 */
00212 
00213     /* Handle the four structures of command APDU */
00214     indexApdu = 4;
00215 
00216     if( wLength == 4 ) {
00217         cmdCase = CASE1;
00218         NeNc = 0;
00219     } else if( wLength == 5) {
00220         cmdCase = CASE2;
00221         NeNc = pAPDU[4]; /* C5 */
00222         if (NeNc == 0) {
00223             NeNc = 256;
00224         }
00225     } else if( wLength == 6) {
00226         NeNc = pAPDU[4]; /* C5 */
00227         cmdCase = CASE3;
00228     } else if( wLength == 7) {
00229         NeNc = pAPDU[4]; /* C5 */
00230         if( NeNc == 0 ) {
00231             cmdCase = CASE2;
00232             NeNc = (pAPDU[5]<<8)+pAPDU[6];
00233         } else {
00234             cmdCase = CASE3;
00235         }
00236     } else {
00237         NeNc = pAPDU[4]; /* C5 */
00238         if( NeNc == 0 ) {
00239             cmdCase = CASE3;
00240             NeNc = (pAPDU[5]<<8)+pAPDU[6];
00241         } else {
00242             cmdCase = CASE3;
00243         }
00244     }
00245 
00246     TRACE_DEBUG("CASE=0x%X NeNc=0x%X\n\r", cmdCase, NeNc);
00247 
00248     /* Handle Procedure Bytes */
00249     do {
00250         ISO7816_GetChar(&procByte);
00251         ins = procByte ^ 0xff;
00252         /* Handle NULL */
00253         if ( procByte == ISO_NULL_VAL ) {
00254             TRACE_DEBUG("INS\n\r");
00255             continue;
00256         }
00257         /* Handle SW1 */
00258         else if ( ((procByte & 0xF0) ==0x60) || ((procByte & 0xF0) ==0x90) ) {
00259             TRACE_DEBUG("SW1\n\r");
00260             SW1 = 1;
00261         }
00262         /* Handle INS */
00263         else if ( pAPDU[1] == procByte) {
00264             TRACE_DEBUG("HdlINS\n\r");
00265             if (cmdCase == CASE2) {
00266                 /* receive data from card */
00267                 do {
00268                     ISO7816_GetChar(&pMessage[indexMessage++]);
00269                 } while( 0 != --NeNc );
00270             } else {
00271                  /* Send data */
00272                 do {
00273                     ISO7816_SendChar(pAPDU[indexApdu++]);
00274                 } while( 0 != --NeNc );
00275             }
00276         }
00277         /* Handle INS ^ 0xff */
00278         else if ( pAPDU[1] == ins) {
00279             TRACE_DEBUG("HdlINS+\n\r");
00280             if (cmdCase == CASE2) {
00281                 /* receive data from card */
00282                 ISO7816_GetChar(&pMessage[indexMessage++]);
00283             } else {
00284                 ISO7816_SendChar(pAPDU[indexApdu++]);
00285             }
00286             NeNc--;
00287         } else {
00288             /* ?? */
00289             TRACE_DEBUG("procByte=0x%X\n\r", procByte);
00290             break;
00291         }
00292     } while (NeNc != 0);
00293 
00294     /* Status Bytes */
00295     if (SW1 == 0) {
00296         ISO7816_GetChar(&pMessage[indexMessage++]); /* SW1 */
00297     } else {
00298         pMessage[indexMessage++] = procByte;
00299     }
00300     ISO7816_GetChar(&pMessage[indexMessage++]); /* SW2 */
00301 
00302     return( indexMessage );
00303 
00304 }
00305 
00306 /**
00307  *  Escape ISO7816
00308  */
00309 void ISO7816_Escape( void )
00310 {
00311     TRACE_DEBUG("For user, if needed\n\r");
00312 }
00313 
00314 /**
00315  *  Restart clock ISO7816
00316  */
00317 void ISO7816_RestartClock( void )
00318 {
00319     TRACE_DEBUG("ISO7816_RestartClock\n\r");
00320     UsartIso->US_BRGR = 13;
00321 }
00322 
00323 /**
00324  *  Stop clock ISO7816
00325  */
00326 void ISO7816_StopClock( void )
00327 {
00328     TRACE_DEBUG("ISO7816_StopClock\n\r");
00329     UsartIso->US_BRGR = 0;
00330 }
00331 
00332 /**
00333  *  T0 APDU
00334  */
00335 void ISO7816_toAPDU( void )
00336 {
00337     TRACE_DEBUG("ISO7816_toAPDU\n\r");
00338     TRACE_DEBUG("Not supported at this time\n\r");
00339 }
00340 
00341 /**
00342  * Answer To Reset (ATR)
00343  * \param pAtr    ATR buffer
00344  * \param pLength Pointer for store the ATR length
00345  */
00346 void ISO7816_Datablock_ATR( uint8_t* pAtr, uint8_t* pLength )
00347 {
00348     uint32_t i;
00349     uint32_t j;
00350     uint32_t y;
00351 
00352     *pLength = 0;
00353 
00354     /* Read ATR TS */
00355     ISO7816_GetChar(&pAtr[0]);
00356     /* Read ATR T0 */
00357     ISO7816_GetChar(&pAtr[1]);
00358     y = pAtr[1] & 0xF0;
00359     i = 2;
00360 
00361     /* Read ATR Ti */
00362     while (y) {
00363         if (y & 0x10) {  /* TA[i] */
00364             ISO7816_GetChar(&pAtr[i++]);
00365         }
00366         if (y & 0x20) {  /* TB[i] */
00367             ISO7816_GetChar(&pAtr[i++]);
00368         }
00369         if (y & 0x40) {  /* TC[i] */
00370             ISO7816_GetChar(&pAtr[i++]);
00371         }
00372         if (y & 0x80) {  /* TD[i] */
00373             ISO7816_GetChar(&pAtr[i]);
00374             y =  pAtr[i++] & 0xF0;
00375         } else {
00376             y = 0;
00377         }
00378     }
00379 
00380     /* Historical Bytes */
00381     y = pAtr[1] & 0x0F;
00382     for( j=0; j < y; j++ ) {
00383         ISO7816_GetChar(&pAtr[i++]);
00384     }
00385 
00386     *pLength = i;
00387 
00388 }
00389 
00390 /**
00391  * Set data rate and clock frequency
00392  * \param dwClockFrequency ICC clock frequency in KHz.
00393  * \param dwDataRate       ICC data rate in bpd
00394  */
00395 void ISO7816_SetDataRateandClockFrequency( uint32_t dwClockFrequency, 
00396         uint32_t dwDataRate )
00397 {
00398     uint8_t ClockFrequency;
00399 
00400     /* Define the baud rate divisor register */
00401     /* CD  = MCK / SCK */
00402     /* SCK = FIDI x BAUD = 372 x 9600 */
00403     /* BOARD_MCK */
00404     /* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */
00405     UsartIso->US_BRGR = BOARD_MCK / (dwClockFrequency*1000);
00406 
00407     ClockFrequency = BOARD_MCK / UsartIso->US_BRGR;
00408 
00409     UsartIso->US_FIDI = (ClockFrequency)/dwDataRate;
00410 
00411 }
00412 
00413 /**
00414  * Pin status for ISO7816 RESET
00415  * \return 1 if the Pin RstMC is high; otherwise 0.
00416  */
00417 uint8_t ISO7816_StatusReset( void )
00418 {
00419     return PIO_Get(&st_pinIso7816RstMC);
00420 }
00421 
00422 /**
00423  *  cold reset
00424  */
00425 void ISO7816_cold_reset( void )
00426 {
00427     volatile uint32_t i;
00428 
00429     /* tb: wait 400 cycles*/
00430     for( i=0; i<(120*(BOARD_MCK/1000000)); i++ ) {
00431     }
00432 
00433     UsartIso->US_RHR;
00434     UsartIso->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
00435 
00436     ISO7816_IccPowerOn();
00437 }
00438 
00439 /**
00440  *  Warm reset
00441  */
00442 void ISO7816_warm_reset( void )
00443 {
00444     volatile uint32_t i;
00445 
00446     ISO7816_IccPowerOff();
00447 
00448     /* tb: wait 400 cycles */
00449     for( i=0; i<(120*(BOARD_MCK/1000000)); i++ ) {
00450     }
00451 
00452     UsartIso->US_RHR;
00453     UsartIso->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
00454 
00455     ISO7816_IccPowerOn();
00456 }
00457 
00458 /**
00459  * Decode ATR trace
00460  * \param pAtr pointer on ATR buffer
00461  */
00462 void ISO7816_Decode_ATR( uint8_t* pAtr )
00463 {
00464     uint32_t i;
00465     uint32_t j;
00466     uint32_t y;
00467     uint8_t offset;
00468 
00469     printf("\n\r");
00470     printf("ATR: Answer To Reset:\n\r");
00471     printf("TS = 0x%X Initial character ",pAtr[0]);
00472     if( pAtr[0] == 0x3B ) {
00473 
00474         printf("Direct Convention\n\r");
00475     } else {
00476         if( pAtr[0] == 0x3F ) {
00477             printf("Inverse Convention\n\r");
00478         } else {
00479             printf("BAD Convention\n\r");
00480         }
00481     }
00482 
00483     printf("T0 = 0x%X Format character\n\r",pAtr[1]);
00484     printf("    Number of historical bytes: K = %d\n\r", pAtr[1]&0x0F);
00485     printf("    Presence further interface byte:\n\r");
00486     if( pAtr[1]&0x10 ) {
00487         printf("TA ");
00488     }
00489     if( pAtr[1]&0x20 ) {
00490         printf("TB ");
00491     }
00492     if( pAtr[1]&0x40 ) {
00493         printf("TC ");
00494     }
00495     if( pAtr[1]&0x80 ) {
00496         printf("TD ");
00497     }
00498     if( pAtr[1] != 0 ) {
00499         printf(" present\n\r");
00500     }
00501 
00502     i = 2;
00503     y = pAtr[1] & 0xF0;
00504 
00505     /* Read ATR Ti */
00506     offset = 1;
00507     while (y) {
00508 
00509         if (y & 0x10) {  /* TA[i] */
00510             printf("TA[%d] = 0x%X ", offset, pAtr[i]);
00511             if( offset == 1 ) {
00512                 printf("FI = %d ", (pAtr[i]>>4));
00513                 printf("DI = %d", (pAtr[i]&0x0F));
00514             }
00515             printf("\n\r");
00516             i++;
00517         }
00518         if (y & 0x20) {  /* TB[i] */
00519             printf("TB[%d] = 0x%X\n\r", offset, pAtr[i]);
00520             i++;
00521         }
00522         if (y & 0x40) {  /* TC[i] */
00523             printf("TC[%d] = 0x%X ", offset, pAtr[i]);
00524             if( offset == 1 ) {
00525                 printf("Extra Guard Time: N = %d", pAtr[i]);
00526             }
00527             printf("\n\r");
00528             i++;
00529         }
00530         if (y & 0x80) {  /* TD[i] */
00531             printf("TD[%d] = 0x%X\n\r", offset, pAtr[i]);
00532             y =  pAtr[i++] & 0xF0;
00533         } else {
00534             y = 0;
00535         }
00536         offset++;
00537     }
00538 
00539     /* Historical Bytes */
00540     printf("Historical bytes:\n\r");
00541     y = pAtr[1] & 0x0F;
00542     for( j=0; j < y; j++ ) {
00543         printf(" 0x%X", pAtr[i]);
00544         if( (pAtr[i] > 0x21) && (pAtr[i] < 0x7D) ) {  /* ASCII */
00545             printf("(%c) ", pAtr[i]);
00546         }
00547         i++;
00548     }
00549     printf("\n\r\n\r");
00550 
00551 }
00552 
00553 /** Initializes a ISO driver
00554  * \param pUsart   Pointer to the USART peripheral to configure.
00555  * \param usartId USART ID for iso7816
00556  *  \param pPinIso7816RstMC Pin ISO 7816 Rst MC
00557  */
00558 void ISO7816_Init( Usart *pUsart, uint32_t usartId , const Pin pPinIso7816RstMC )
00559 {
00560     TRACE_DEBUG("ISO_Init\n\r");
00561     UsartIso = pUsart;
00562     UsartIsoId = usartId;
00563         uint32_t baudrate = USART7816BAUDRATE;
00564         
00565     /* Pin ISO7816 initialize */
00566     st_pinIso7816RstMC  = pPinIso7816RstMC;
00567     
00568         PMC_EnablePeripheral(UsartIsoId);
00569 
00570         UsartIso->US_FIDI = 372;  /* by default */
00571 
00572         /* Configure USART */
00573     USART_Configure( UsartIso,
00574                      US_MR_USART_MODE_IS07816_T_0
00575                      | US_MR_USCLKS_MCK
00576                      | US_MR_NBSTOP_1_BIT
00577                      | US_MR_PAR_EVEN
00578                      | US_MR_CHRL_8_BIT
00579                      | US_MR_CLKO
00580                      | (3<<24), /* MAX_ITERATION */
00581                      baudrate,
00582                      BOARD_MCK);
00583 
00584     /* Write the Time-guard Register */
00585     UsartIso->US_TTGR = 5;
00586 }
00587 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines