1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2012, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
39 * Explanation on the usage of the code made available through the header file.
\r
42 /*------------------------------------------------------------------------------
\r
44 *------------------------------------------------------------------------------*/
\r
48 /*------------------------------------------------------------------------------
\r
50 *------------------------------------------------------------------------------*/
\r
51 /** Case for APDU commands*/
\r
56 /** Flip flop for send and receive char */
\r
57 #define USART_SEND 0
\r
60 #if !defined(BOARD_ISO7816_BASE_USART)
\r
61 #define BOARD_ISO7816_BASE_USART USART1
\r
62 #define BOARD_ISO7816_ID_USART ID_USART1
\r
65 /*-----------------------------------------------------------------------------
\r
66 * Internal variables
\r
67 *-----------------------------------------------------------------------------*/
\r
68 /** Variable for state of send and receive froom USART */
\r
69 static uint8_t StateUsartGlobal = USART_RCV;
\r
70 /** Pin reset master card */
\r
71 static Pin st_pinIso7816RstMC;
\r
73 /*----------------------------------------------------------------------------
\r
74 * Internal functions
\r
75 *----------------------------------------------------------------------------*/
\r
78 * Get a character from ISO7816
\r
79 * \param pCharToReceive Pointer for store the received char
\r
80 * \return 0: if timeout else status of US_CSR
\r
82 static uint32_t ISO7816_GetChar( uint8_t *pCharToReceive )
\r
87 if( StateUsartGlobal == USART_SEND ) {
\r
88 while((BOARD_ISO7816_BASE_USART->US_CSR & US_CSR_TXEMPTY) == 0) {}
\r
89 BOARD_ISO7816_BASE_USART->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
\r
90 StateUsartGlobal = USART_RCV;
\r
93 /* Wait USART ready for reception */
\r
94 while( ((BOARD_ISO7816_BASE_USART->US_CSR & US_CSR_RXRDY) == 0) ) {
\r
95 if(timeout++ > 12000 * (BOARD_MCK/1000000)) {
\r
96 TRACE_DEBUG("TimeOut\n\r");
\r
101 TRACE_DEBUG("T: %u\n\r", timeout);
\r
104 /* At least one complete character has been received and US_RHR has not yet been read. */
\r
107 *pCharToReceive = ((BOARD_ISO7816_BASE_USART->US_RHR) & 0xFF);
\r
109 status = (BOARD_ISO7816_BASE_USART->US_CSR&(US_CSR_OVRE|US_CSR_FRAME|
\r
110 US_CSR_PARE|US_CSR_TIMEOUT|US_CSR_NACK|
\r
113 if (status != 0 ) {
\r
114 /* TRACE_DEBUG("R:0x%X\n\r", status); */
\r
115 TRACE_DEBUG("R:0x%X\n\r", BOARD_ISO7816_BASE_USART->US_CSR);
\r
116 TRACE_DEBUG("Nb:0x%X\n\r", BOARD_ISO7816_BASE_USART->US_NER );
\r
117 BOARD_ISO7816_BASE_USART->US_CR = US_CR_RSTSTA;
\r
120 /* Return status */
\r
126 * Send a char to ISO7816
\r
127 * \param CharToSend char to be send
\r
128 * \return status of US_CSR
\r
130 static uint32_t ISO7816_SendChar( uint8_t CharToSend )
\r
134 if( StateUsartGlobal == USART_RCV ) {
\r
135 BOARD_ISO7816_BASE_USART->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
\r
136 StateUsartGlobal = USART_SEND;
\r
139 /* Wait USART ready for transmit */
\r
140 while((BOARD_ISO7816_BASE_USART->US_CSR & US_CSR_TXRDY) == 0) {}
\r
141 /* There is no character in the US_THR */
\r
143 /* Transmit a char */
\r
144 BOARD_ISO7816_BASE_USART->US_THR = CharToSend;
\r
146 status = (BOARD_ISO7816_BASE_USART->US_CSR&(US_CSR_OVRE|US_CSR_FRAME|
\r
147 US_CSR_PARE|US_CSR_TIMEOUT|US_CSR_NACK|
\r
150 if (status != 0 ) {
\r
151 TRACE_DEBUG("E:0x%X\n\r", BOARD_ISO7816_BASE_USART->US_CSR);
\r
152 TRACE_DEBUG("Nb:0x%X\n\r", BOARD_ISO7816_BASE_USART->US_NER );
\r
153 BOARD_ISO7816_BASE_USART->US_CR = US_CR_RSTSTA;
\r
156 /* Return status */
\r
162 * Iso 7816 ICC power on
\r
164 static void ISO7816_IccPowerOn( void )
\r
166 /* Set RESET Master Card */
\r
167 PIO_Set(&st_pinIso7816RstMC);
\r
170 /*----------------------------------------------------------------------------
\r
171 * Exported functions
\r
172 *----------------------------------------------------------------------------*/
\r
175 * Iso 7816 ICC power off
\r
177 void ISO7816_IccPowerOff( void )
\r
179 /* Clear RESET Master Card */
\r
180 PIO_Clear(&st_pinIso7816RstMC);
\r
184 * Transfert Block TPDU T=0
\r
185 * \param pAPDU APDU buffer
\r
186 * \param pMessage Message buffer
\r
187 * \param wLength Block length
\r
188 * \return Message index
\r
190 uint16_t ISO7816_XfrBlockTPDU_T0(const uint8_t *pAPDU,
\r
195 uint16_t indexApdu = 4;
\r
196 uint16_t indexMessage = 0;
\r
202 TRACE_DEBUG("pAPDU[0]=0x%X\n\r",pAPDU[0]);
\r
203 TRACE_DEBUG("pAPDU[1]=0x%X\n\r",pAPDU[1]);
\r
204 TRACE_DEBUG("pAPDU[2]=0x%X\n\r",pAPDU[2]);
\r
205 TRACE_DEBUG("pAPDU[3]=0x%X\n\r",pAPDU[3]);
\r
206 TRACE_DEBUG("pAPDU[4]=0x%X\n\r",pAPDU[4]);
\r
207 TRACE_DEBUG("pAPDU[5]=0x%X\n\r",pAPDU[5]);
\r
208 TRACE_DEBUG("wlength=%d\n\r",wLength);
\r
210 ISO7816_SendChar( pAPDU[0] ); /* CLA */
\r
211 ISO7816_SendChar( pAPDU[1] ); /* INS */
\r
212 ISO7816_SendChar( pAPDU[2] ); /* P1 */
\r
213 ISO7816_SendChar( pAPDU[3] ); /* P2 */
\r
214 ISO7816_SendChar( pAPDU[4] ); /* P3 */
\r
216 /* Handle the four structures of command APDU */
\r
219 if( wLength == 4 ) {
\r
223 else if( wLength == 5) {
\r
225 NeNc = pAPDU[4]; /* C5 */
\r
230 else if( wLength == 6) {
\r
231 NeNc = pAPDU[4]; /* C5 */
\r
234 else if( wLength == 7) {
\r
235 NeNc = pAPDU[4]; /* C5 */
\r
238 NeNc = (pAPDU[5]<<8)+pAPDU[6];
\r
245 NeNc = pAPDU[4]; /* C5 */
\r
248 NeNc = (pAPDU[5]<<8)+pAPDU[6];
\r
255 TRACE_DEBUG("CASE=0x%X NeNc=0x%X\n\r", cmdCase, NeNc);
\r
257 /* Handle Procedure Bytes */
\r
259 ISO7816_GetChar(&procByte);
\r
260 ins = procByte ^ 0xff;
\r
262 if ( procByte == ISO_NULL_VAL ) {
\r
263 TRACE_DEBUG("INS\n\r");
\r
267 else if ( ((procByte & 0xF0) ==0x60) || ((procByte & 0xF0) ==0x90) ) {
\r
268 TRACE_DEBUG("SW1\n\r");
\r
272 else if ( pAPDU[1] == procByte) {
\r
273 TRACE_DEBUG("HdlINS\n\r");
\r
274 if (cmdCase == CASE2) {
\r
275 /* receive data from card */
\r
277 ISO7816_GetChar(&pMessage[indexMessage++]);
\r
278 } while( 0 != --NeNc );
\r
283 ISO7816_SendChar(pAPDU[indexApdu++]);
\r
284 } while( 0 != --NeNc );
\r
287 /* Handle INS ^ 0xff */
\r
288 else if ( pAPDU[1] == ins) {
\r
289 TRACE_DEBUG("HdlINS+\n\r");
\r
290 if (cmdCase == CASE2) {
\r
291 /* receive data from card */
\r
292 ISO7816_GetChar(&pMessage[indexMessage++]);
\r
295 ISO7816_SendChar(pAPDU[indexApdu++]);
\r
301 TRACE_DEBUG("procByte=0x%X\n\r", procByte);
\r
304 } while (NeNc != 0);
\r
308 ISO7816_GetChar(&pMessage[indexMessage++]); /* SW1 */
\r
311 pMessage[indexMessage++] = procByte;
\r
313 ISO7816_GetChar(&pMessage[indexMessage++]); /* SW2 */
\r
315 return( indexMessage );
\r
322 void ISO7816_Escape( void )
\r
324 TRACE_DEBUG("For user, if needed\n\r");
\r
328 * Restart clock ISO7816
\r
330 void ISO7816_RestartClock( void )
\r
332 TRACE_DEBUG("ISO7816_RestartClock\n\r");
\r
333 BOARD_ISO7816_BASE_USART->US_BRGR = 13;
\r
337 * Stop clock ISO7816
\r
339 void ISO7816_StopClock( void )
\r
341 TRACE_DEBUG("ISO7816_StopClock\n\r");
\r
342 BOARD_ISO7816_BASE_USART->US_BRGR = 0;
\r
348 void ISO7816_toAPDU( void )
\r
350 TRACE_DEBUG("ISO7816_toAPDU\n\r");
\r
351 TRACE_DEBUG("Not supported at this time\n\r");
\r
355 * Answer To Reset (ATR)
\r
356 * \param pAtr ATR buffer
\r
357 * \param pLength Pointer for store the ATR length
\r
359 void ISO7816_Datablock_ATR( uint8_t* pAtr, uint8_t* pLength )
\r
368 ISO7816_GetChar(&pAtr[0]);
\r
370 ISO7816_GetChar(&pAtr[1]);
\r
371 y = pAtr[1] & 0xF0;
\r
377 if (y & 0x10) { /* TA[i] */
\r
378 ISO7816_GetChar(&pAtr[i++]);
\r
380 if (y & 0x20) { /* TB[i] */
\r
381 ISO7816_GetChar(&pAtr[i++]);
\r
383 if (y & 0x40) { /* TC[i] */
\r
384 ISO7816_GetChar(&pAtr[i++]);
\r
386 if (y & 0x80) { /* TD[i] */
\r
387 ISO7816_GetChar(&pAtr[i]);
\r
388 y = pAtr[i++] & 0xF0;
\r
395 /* Historical Bytes */
\r
396 y = pAtr[1] & 0x0F;
\r
397 for( j=0; j < y; j++ ) {
\r
398 ISO7816_GetChar(&pAtr[i++]);
\r
406 * Set data rate and clock frequency
\r
407 * \param dwClockFrequency ICC clock frequency in KHz.
\r
408 * \param dwDataRate ICC data rate in bpd
\r
410 void ISO7816_SetDataRateandClockFrequency( uint32_t dwClockFrequency, uint32_t dwDataRate )
\r
412 uint8_t ClockFrequency;
\r
414 /* Define the baud rate divisor register */
\r
415 /* CD = MCK / SCK */
\r
416 /* SCK = FIDI x BAUD = 372 x 9600 */
\r
418 /* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */
\r
419 BOARD_ISO7816_BASE_USART->US_BRGR = BOARD_MCK / (dwClockFrequency*1000);
\r
421 ClockFrequency = BOARD_MCK / BOARD_ISO7816_BASE_USART->US_BRGR;
\r
423 BOARD_ISO7816_BASE_USART->US_FIDI = (ClockFrequency)/dwDataRate;
\r
428 * Pin status for ISO7816 RESET
\r
429 * \return 1 if the Pin RstMC is high; otherwise 0.
\r
431 uint8_t ISO7816_StatusReset( void )
\r
433 return PIO_Get(&st_pinIso7816RstMC);
\r
439 void ISO7816_cold_reset( void )
\r
441 volatile uint32_t i;
\r
443 /* tb: wait 400 cycles*/
\r
444 for( i=0; i<(120*(BOARD_MCK/1000000)); i++ ) {
\r
447 BOARD_ISO7816_BASE_USART->US_RHR;
\r
448 BOARD_ISO7816_BASE_USART->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
\r
450 ISO7816_IccPowerOn();
\r
456 void ISO7816_warm_reset( void )
\r
458 volatile uint32_t i;
\r
460 ISO7816_IccPowerOff();
\r
462 /* tb: wait 400 cycles */
\r
463 for( i=0; i<(120*(BOARD_MCK/1000000)); i++ ) {
\r
466 BOARD_ISO7816_BASE_USART->US_RHR;
\r
467 BOARD_ISO7816_BASE_USART->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
\r
469 ISO7816_IccPowerOn();
\r
474 * \param pAtr pointer on ATR buffer
\r
476 void ISO7816_Decode_ATR( uint8_t* pAtr )
\r
484 printf("ATR: Answer To Reset:\n\r");
\r
485 printf("TS = 0x%X Initial character ",pAtr[0]);
\r
486 if( pAtr[0] == 0x3B ) {
\r
488 printf("Direct Convention\n\r");
\r
491 if( pAtr[0] == 0x3F ) {
\r
493 printf("Inverse Convention\n\r");
\r
496 printf("BAD Convention\n\r");
\r
500 printf("T0 = 0x%X Format caracter\n\r",pAtr[1]);
\r
501 printf(" Number of historical bytes: K = %d\n\r", pAtr[1]&0x0F);
\r
502 printf(" Presence further interface byte:\n\r");
\r
503 if( pAtr[1]&0x80 ) {
\r
506 if( pAtr[1]&0x40 ) {
\r
509 if( pAtr[1]&0x20 ) {
\r
512 if( pAtr[1]&0x10 ) {
\r
515 if( pAtr[1] != 0 ) {
\r
516 printf(" present\n\r");
\r
520 y = pAtr[1] & 0xF0;
\r
526 if (y & 0x10) { /* TA[i] */
\r
527 printf("TA[%d] = 0x%X ", offset, pAtr[i]);
\r
528 if( offset == 1 ) {
\r
529 printf("FI = %d ", (pAtr[i]>>8));
\r
530 printf("DI = %d", (pAtr[i]&0x0F));
\r
535 if (y & 0x20) { /* TB[i] */
\r
536 printf("TB[%d] = 0x%X\n\r", offset, pAtr[i]);
\r
539 if (y & 0x40) { /* TC[i] */
\r
540 printf("TC[%d] = 0x%X ", offset, pAtr[i]);
\r
541 if( offset == 1 ) {
\r
542 printf("Extra Guard Time: N = %d", pAtr[i]);
\r
547 if (y & 0x80) { /* TD[i] */
\r
548 printf("TD[%d] = 0x%X\n\r", offset, pAtr[i]);
\r
549 y = pAtr[i++] & 0xF0;
\r
557 /* Historical Bytes */
\r
558 printf("Historical bytes:\n\r");
\r
559 y = pAtr[1] & 0x0F;
\r
560 for( j=0; j < y; j++ ) {
\r
562 printf(" 0x%X", pAtr[i]);
\r
563 if( (pAtr[i] > 0x21) && (pAtr[i] < 0x7D) ) { /* ASCII */
\r
564 printf("(%c) ", pAtr[i]);
\r
568 printf("\n\r\n\r");
\r
572 /** Initializes a ISO driver
\r
573 * \param pPinIso7816RstMC Pin ISO 7816 Rst MC
\r
575 void ISO7816_Init( const Pin pPinIso7816RstMC )
\r
577 TRACE_DEBUG("ISO_Init\n\r");
\r
579 /* Pin ISO7816 initialize */
\r
580 st_pinIso7816RstMC = pPinIso7816RstMC;
\r
582 USART_Configure( BOARD_ISO7816_BASE_USART,
\r
583 US_MR_USART_MODE_IS07816_T_0
\r
585 | US_MR_NBSTOP_1_BIT
\r
589 | (3<<24), /* MAX_ITERATION */
\r
593 /* Configure USART */
\r
594 PMC_EnablePeripheral(BOARD_ISO7816_ID_USART);
\r
595 /* Disable interrupts */
\r
596 BOARD_ISO7816_BASE_USART->US_IDR = (uint32_t) -1;
\r
598 BOARD_ISO7816_BASE_USART->US_FIDI = 372; /* by default */
\r
599 /* Define the baud rate divisor register */
\r
600 /* CD = MCK / SCK */
\r
601 /* SCK = FIDI x BAUD = 372 x 9600 */
\r
603 /* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */
\r
604 BOARD_ISO7816_BASE_USART->US_BRGR = BOARD_MCK / (372*9600);
\r
606 /* Write the Timeguard Register */
\r
607 BOARD_ISO7816_BASE_USART->US_TTGR = 5;
\r
609 USART_SetTransmitterEnabled(BOARD_ISO7816_BASE_USART, 1);
\r
610 USART_SetReceiverEnabled(BOARD_ISO7816_BASE_USART, 1);
\r