blob: 34b84a954307a6e6806a9f1dce7d2b856e49f712 [file] [log] [blame]
Christina Quast32a90ac2015-03-10 16:18:16 +01001/* ----------------------------------------------------------------------------
2 * ATMEL Microcontroller Software Support
3 * ----------------------------------------------------------------------------
4 * Copyright (c) 2009, Atmel Corporation
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the disclaimer below.
13 *
14 * Atmel's name may not be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * ----------------------------------------------------------------------------
28 */
29
30/**
31 * \file
32 *
33 * \section Purpose
34 *
35 * ISO 7816 driver
36 *
37 * \section Usage
38 *
39 * Explanation on the usage of the code made available through the header file.
40 */
41
42/*------------------------------------------------------------------------------
43 * Headers
44 *------------------------------------------------------------------------------*/
45
46#include "board.h"
47
48/*------------------------------------------------------------------------------
49 * Definitions
50 *------------------------------------------------------------------------------*/
51/** Case for APDU commands*/
52#define CASE1 1
53#define CASE2 2
54#define CASE3 3
55
56/** Flip flop for send and receive char */
57#define USART_SEND 0
58#define USART_RCV 1
59
Christina Quast32a90ac2015-03-10 16:18:16 +010060/*-----------------------------------------------------------------------------
61 * Internal variables
62 *-----------------------------------------------------------------------------*/
Christina Quast32a90ac2015-03-10 16:18:16 +010063/** Pin reset master card */
Christina Quast2fcef412015-03-10 15:51:21 +010064static Pin *st_pinIso7816RstMC;
Christina Quast32a90ac2015-03-10 16:18:16 +010065
Christina Quastec9c09e2015-04-16 10:45:39 +020066struct Usart_info usart_sim = {.base = USART_SIM, .id = ID_USART_SIM, .state = USART_RCV};
Christina Quaste24b9ac2015-04-10 17:44:49 +020067
Christina Quast32a90ac2015-03-10 16:18:16 +010068/*----------------------------------------------------------------------------
69 * Internal functions
70 *----------------------------------------------------------------------------*/
71
72/**
73 * Get a character from ISO7816
74 * \param pCharToReceive Pointer for store the received char
75 * \return 0: if timeout else status of US_CSR
76 */
Christina Quaste24b9ac2015-04-10 17:44:49 +020077uint32_t ISO7816_GetChar( uint8_t *pCharToReceive, Usart_info *usart)
Christina Quast32a90ac2015-03-10 16:18:16 +010078{
Kévin Redon33d1eb72018-07-08 13:58:12 +020079 uint32_t status;
80 uint32_t timeout=0;
Christina Quast32a90ac2015-03-10 16:18:16 +010081
Kévin Redon33d1eb72018-07-08 13:58:12 +020082 Usart *us_base = usart->base;
83 uint32_t us_id = usart->id;
Christina Quaste24b9ac2015-04-10 17:44:49 +020084
Kévin Redon33d1eb72018-07-08 13:58:12 +020085 if( usart->state == USART_SEND ) {
86 while((us_base->US_CSR & US_CSR_TXEMPTY) == 0) {}
87 us_base->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
88 usart->state = USART_RCV;
89 }
Christina Quast32a90ac2015-03-10 16:18:16 +010090
Kévin Redon33d1eb72018-07-08 13:58:12 +020091 /* Wait USART ready for reception */
92 while( ((us_base->US_CSR & US_CSR_RXRDY) == 0) ) {
Harald Welte0633b252017-11-28 22:47:09 +010093 WDT_Restart(WDT);
Kévin Redon33d1eb72018-07-08 13:58:12 +020094 if(timeout++ > 12000 * (BOARD_MCK/1000000)) {
95 TRACE_WARNING("TimeOut\n\r");
96 return( 0 );
97 }
98 }
Christina Quast32a90ac2015-03-10 16:18:16 +010099
Kévin Redon33d1eb72018-07-08 13:58:12 +0200100 /* At least one complete character has been received and US_RHR has not yet been read. */
Christina Quast32a90ac2015-03-10 16:18:16 +0100101
Kévin Redon33d1eb72018-07-08 13:58:12 +0200102 /* Get a char */
103 *pCharToReceive = ((us_base->US_RHR) & 0xFF);
Christina Quast32a90ac2015-03-10 16:18:16 +0100104
Kévin Redon33d1eb72018-07-08 13:58:12 +0200105 status = (us_base->US_CSR&(US_CSR_OVRE|US_CSR_FRAME|
106 US_CSR_PARE|US_CSR_TIMEOUT|US_CSR_NACK|
107 (1<<10)));
Christina Quast32a90ac2015-03-10 16:18:16 +0100108
Kévin Redon33d1eb72018-07-08 13:58:12 +0200109 if (status != 0 ) {
110 TRACE_DEBUG("R:0x%" PRIX32 "\n\r", status);
111 TRACE_DEBUG("R:0x%" PRIX32 "\n\r", us_base->US_CSR);
112 TRACE_DEBUG("Nb:0x%" PRIX32 "\n\r", us_base->US_NER );
113 us_base->US_CR = US_CR_RSTSTA;
114 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100115
Kévin Redon33d1eb72018-07-08 13:58:12 +0200116 /* Return status */
117 return( status );
Christina Quast32a90ac2015-03-10 16:18:16 +0100118}
119
120
121/**
122 * Send a char to ISO7816
123 * \param CharToSend char to be send
124 * \return status of US_CSR
125 */
Christina Quaste24b9ac2015-04-10 17:44:49 +0200126uint32_t ISO7816_SendChar( uint8_t CharToSend, Usart_info *usart )
Christina Quast32a90ac2015-03-10 16:18:16 +0100127{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200128 uint32_t status;
Christina Quast32a90ac2015-03-10 16:18:16 +0100129
Kévin Redon33d1eb72018-07-08 13:58:12 +0200130 Usart *us_base = usart->base;
131 uint32_t us_id = usart->id;
Christina Quaste24b9ac2015-04-10 17:44:49 +0200132
Kévin Redon33d1eb72018-07-08 13:58:12 +0200133 if( usart->state == USART_RCV ) {
134 us_base->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
135 usart->state = USART_SEND;
136 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100137
Kévin Redon33d1eb72018-07-08 13:58:12 +0200138 /* Wait USART ready for transmit */
139 int i = 0;
140 while((us_base->US_CSR & (US_CSR_TXRDY)) == 0) {
141 i++;
142 if (!(i%1000000)) {
Harald Weltec3941092018-08-26 09:53:13 +0200143 printf("s: %lx ", us_base->US_CSR);
144 printf("s: %lx\r\n", us_base->US_RHR & 0xFF);
Kévin Redon33d1eb72018-07-08 13:58:12 +0200145 us_base->US_CR = US_CR_RSTTX;
146 us_base->US_CR = US_CR_RSTRX;
147 }
148 }
149 /* There is no character in the US_THR */
Christina Quast32a90ac2015-03-10 16:18:16 +0100150
Kévin Redon33d1eb72018-07-08 13:58:12 +0200151 /* Transmit a char */
152 us_base->US_THR = CharToSend;
Christina Quast32a90ac2015-03-10 16:18:16 +0100153
Kévin Redon33d1eb72018-07-08 13:58:12 +0200154 TRACE_ERROR("Sx%02X\r\n", CharToSend);
Harald Welte40901a02016-03-03 10:42:45 +0100155
Kévin Redon33d1eb72018-07-08 13:58:12 +0200156 status = (us_base->US_CSR&(US_CSR_OVRE|US_CSR_FRAME|
157 US_CSR_PARE|US_CSR_TIMEOUT|US_CSR_NACK|
158 (1<<10)));
Christina Quast32a90ac2015-03-10 16:18:16 +0100159
Kévin Redon33d1eb72018-07-08 13:58:12 +0200160 if (status != 0 ) {
161 TRACE_INFO("******* status: 0x%" PRIX32 " (Overrun: %" PRIX32
162 ", NACK: %" PRIX32 ", Timeout: %" PRIX32 ", underrun: %" PRIX32 ")\n\r",
163 status, ((status & US_CSR_OVRE)>> 5), ((status & US_CSR_NACK) >> 13),
164 ((status & US_CSR_TIMEOUT) >> 8), ((status & (1 << 10)) >> 10));
165 TRACE_INFO("E (USART CSR reg):0x%" PRIX32 "\n\r", us_base->US_CSR);
166 TRACE_INFO("Nb (Number of errors):0x%" PRIX32 "\n\r", us_base->US_NER );
167 us_base->US_CR = US_CR_RSTSTA;
168 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100169
Kévin Redon33d1eb72018-07-08 13:58:12 +0200170 /* Return status */
171 return( status );
Christina Quast32a90ac2015-03-10 16:18:16 +0100172}
173
174
175/**
176 * Iso 7816 ICC power on
177 */
178static void ISO7816_IccPowerOn( void )
179{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200180 /* Set RESET Master Card */
181 if (st_pinIso7816RstMC) {
182 PIO_Set(st_pinIso7816RstMC);
183 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100184}
185
186/*----------------------------------------------------------------------------
187 * Exported functions
188 *----------------------------------------------------------------------------*/
189
190/**
191 * Iso 7816 ICC power off
192 */
193void ISO7816_IccPowerOff( void )
194{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200195 /* Clear RESET Master Card */
196 if (st_pinIso7816RstMC) {
197 PIO_Clear(st_pinIso7816RstMC);
198 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100199}
200
201/**
Christina Quast73c2b642015-04-07 13:49:26 +0200202 * Transfert Block TPDU T=0
203 * \param pAPDU APDU buffer
204 * \param pMessage Message buffer
205 * \param wLength Block length
206 * \param indexMsg Message index
207 * \return 0 on success, content of US_CSR otherwise
Christina Quast32a90ac2015-03-10 16:18:16 +0100208 */
Christina Quast73c2b642015-04-07 13:49:26 +0200209uint32_t ISO7816_XfrBlockTPDU_T0(const uint8_t *pAPDU,
Kévin Redon33d1eb72018-07-08 13:58:12 +0200210 uint8_t *pMessage,
211 uint16_t wLength,
212 uint16_t *retlen )
Christina Quast32a90ac2015-03-10 16:18:16 +0100213{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200214 uint16_t NeNc;
215 uint16_t indexApdu = 4;
216 uint16_t indexMsg = 0;
217 uint8_t SW1 = 0;
218 uint8_t procByte;
219 uint8_t cmdCase;
220 uint32_t status = 0;
Christina Quast32a90ac2015-03-10 16:18:16 +0100221
Kévin Redon33d1eb72018-07-08 13:58:12 +0200222 TRACE_INFO("pAPDU[0]=0x%X\n\r",pAPDU[0]);
223 TRACE_INFO("pAPDU[1]=0x%X\n\r",pAPDU[1]);
224 TRACE_INFO("pAPDU[2]=0x%X\n\r",pAPDU[2]);
225 TRACE_INFO("pAPDU[3]=0x%X\n\r",pAPDU[3]);
226 TRACE_INFO("pAPDU[4]=0x%X\n\r",pAPDU[4]);
227 TRACE_INFO("pAPDU[5]=0x%X\n\r",pAPDU[5]);
228 TRACE_INFO("wlength=%d\n\r",wLength);
Christina Quast32a90ac2015-03-10 16:18:16 +0100229
Kévin Redon33d1eb72018-07-08 13:58:12 +0200230 ISO7816_SendChar( pAPDU[0], &usart_sim ); /* CLA */
231 ISO7816_SendChar( pAPDU[1], &usart_sim ); /* INS */
232 ISO7816_SendChar( pAPDU[2], &usart_sim ); /* P1 */
233 ISO7816_SendChar( pAPDU[3], &usart_sim ); /* P2 */
234 ISO7816_SendChar( pAPDU[4], &usart_sim ); /* P3 */
Christina Quast32a90ac2015-03-10 16:18:16 +0100235
Kévin Redon33d1eb72018-07-08 13:58:12 +0200236 /* Handle the four structures of command APDU */
237 indexApdu = 5;
Christina Quast32a90ac2015-03-10 16:18:16 +0100238
Kévin Redon33d1eb72018-07-08 13:58:12 +0200239 if( wLength == 4 ) {
240 cmdCase = CASE1;
241 NeNc = 0;
242 }
243 else if( wLength == 5) {
244 cmdCase = CASE2;
245 NeNc = pAPDU[4]; /* C5 */
246 if (NeNc == 0) {
247 NeNc = 256;
248 }
249 }
250 else if( wLength == 6) {
251 NeNc = pAPDU[4]; /* C5 */
252 cmdCase = CASE3;
253 }
254 else if( wLength == 7) {
255 NeNc = pAPDU[4]; /* C5 */
256 if( NeNc == 0 ) {
257 cmdCase = CASE2;
258 NeNc = (pAPDU[5]<<8)+pAPDU[6];
259 }
260 else {
261 cmdCase = CASE3;
262 }
263 }
264 else {
265 NeNc = pAPDU[4]; /* C5 */
266 if( NeNc == 0 ) {
267 cmdCase = CASE3;
268 NeNc = (pAPDU[5]<<8)+pAPDU[6];
269 }
270 else {
271 cmdCase = CASE3;
272 }
273 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100274
Kévin Redon33d1eb72018-07-08 13:58:12 +0200275 TRACE_DEBUG("CASE=0x%X NeNc=0x%X\n\r", cmdCase, NeNc);
Christina Quast32a90ac2015-03-10 16:18:16 +0100276
Kévin Redon33d1eb72018-07-08 13:58:12 +0200277 /* Handle Procedure Bytes */
278 do {
279 status = ISO7816_GetChar(&procByte, &usart_sim);
280 if (status != 0) {
281 return status;
282 }
283 TRACE_INFO("procByte: 0x%X\n\r", procByte);
284 /* Handle NULL */
285 if ( procByte == ISO_NULL_VAL ) {
286 TRACE_INFO("INS\n\r");
287 continue;
288 }
289 /* Handle SW1 */
290 else if ( ((procByte & 0xF0) ==0x60) || ((procByte & 0xF0) ==0x90) ) {
291 TRACE_INFO("SW1\n\r");
292 SW1 = 1;
293 }
294 /* Handle INS */
295 else if ( pAPDU[1] == procByte) {
296 TRACE_INFO("HdlINS\n\r");
297 if (cmdCase == CASE2) {
298 /* receive data from card */
299 do {
300 status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim);
301 } while(( 0 != --NeNc) && (status == 0) );
302 if (status != 0) {
303 return status;
304 }
305 }
306 else {
307 /* Send data */
308 do {
309 TRACE_INFO("Send %X", pAPDU[indexApdu]);
310 ISO7816_SendChar(pAPDU[indexApdu++], &usart_sim);
311 } while( 0 != --NeNc );
312 }
313 }
314 /* Handle INS ^ 0xff */
315 else
316 #pragma GCC diagnostic push
317 #pragma GCC diagnostic ignored "-Wsign-compare"
318 if ( pAPDU[1] == (procByte ^ 0xff)) {
319 #pragma GCC diagnostic pop
320 TRACE_INFO("HdlINS+\n\r");
321 if (cmdCase == CASE2) {
322 /* receive data from card */
323 status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim);
324 if (status != 0) {
325 return status;
326 }
327 TRACE_INFO("Rcv: 0x%X\n\r", pMessage[indexMsg-1]);
328 }
329 else {
330 status = ISO7816_SendChar(pAPDU[indexApdu++], &usart_sim);
331 if (status != 0) {
332 return status;
333 }
334 }
335 NeNc--;
336 }
337 else {
338 /* ?? */
339 TRACE_INFO("procByte=0x%X\n\r", procByte);
340 break;
341 }
342 } while (NeNc != 0);
Christina Quast32a90ac2015-03-10 16:18:16 +0100343
Kévin Redon33d1eb72018-07-08 13:58:12 +0200344 /* Status Bytes */
345 if (SW1 == 0) {
346 status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim); /* SW1 */
347 if (status != 0) {
348 return status;
349 }
350 }
351 else {
352 pMessage[indexMsg++] = procByte;
353 }
354 status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim); /* SW2 */
355 if (status != 0) {
356 return status;
357 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100358
Kévin Redon33d1eb72018-07-08 13:58:12 +0200359 TRACE_WARNING("SW1=0x%X, SW2=0x%X\n\r", pMessage[indexMsg-2], pMessage[indexMsg-1]);
Christina Quast2fcef412015-03-10 15:51:21 +0100360
Kévin Redon33d1eb72018-07-08 13:58:12 +0200361 *retlen = indexMsg;
362 return status;
Christina Quast32a90ac2015-03-10 16:18:16 +0100363
364}
365
366/**
367 * Escape ISO7816
368 */
369void ISO7816_Escape( void )
370{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200371 TRACE_DEBUG("For user, if needed\n\r");
Christina Quast32a90ac2015-03-10 16:18:16 +0100372}
373
374/**
375 * Restart clock ISO7816
376 */
377void ISO7816_RestartClock( void )
378{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200379 TRACE_DEBUG("ISO7816_RestartClock\n\r");
380 USART_SIM->US_BRGR = 13;
Christina Quast32a90ac2015-03-10 16:18:16 +0100381}
382
383/**
384 * Stop clock ISO7816
385 */
386void ISO7816_StopClock( void )
387{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200388 TRACE_DEBUG("ISO7816_StopClock\n\r");
389 USART_SIM->US_BRGR = 0;
Christina Quast32a90ac2015-03-10 16:18:16 +0100390}
391
392/**
393 * T0 APDU
394 */
395void ISO7816_toAPDU( void )
396{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200397 TRACE_DEBUG("ISO7816_toAPDU\n\r");
398 TRACE_DEBUG("Not supported at this time\n\r");
Christina Quast32a90ac2015-03-10 16:18:16 +0100399}
400
401/**
402 * Answer To Reset (ATR)
403 * \param pAtr ATR buffer
404 * \param pLength Pointer for store the ATR length
405 * \return 0: if timeout else status of US_CSR
406 */
407uint32_t ISO7816_Datablock_ATR( uint8_t* pAtr, uint8_t* pLength )
408{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200409 uint32_t i;
410 uint32_t j;
411 uint32_t y;
412 uint32_t status = 0;
Christina Quast32a90ac2015-03-10 16:18:16 +0100413
Kévin Redon33d1eb72018-07-08 13:58:12 +0200414 *pLength = 0;
Christina Quast32a90ac2015-03-10 16:18:16 +0100415
Kévin Redon33d1eb72018-07-08 13:58:12 +0200416 /* Read ATR TS */
417 // FIXME: There should always be a check for the GetChar return value..0 means timeout
418 status = ISO7816_GetChar(&pAtr[0], &usart_sim);
419 if (status != 0) {
420 return status;
421 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100422
Kévin Redon33d1eb72018-07-08 13:58:12 +0200423 /* Read ATR T0 */
424 status = ISO7816_GetChar(&pAtr[1], &usart_sim);
425 if (status != 0) {
426 return status;
427 }
428 y = pAtr[1] & 0xF0;
429 i = 2;
Christina Quast32a90ac2015-03-10 16:18:16 +0100430
Kévin Redon33d1eb72018-07-08 13:58:12 +0200431 /* Read ATR Ti */
432 while (y && (status == 0)) {
Christina Quast32a90ac2015-03-10 16:18:16 +0100433
Kévin Redon33d1eb72018-07-08 13:58:12 +0200434 if (y & 0x10) { /* TA[i] */
435 status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
436 }
437 if (y & 0x20) { /* TB[i] */
438 status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
439 }
440 if (y & 0x40) { /* TC[i] */
441 status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
442 }
443 if (y & 0x80) { /* TD[i] */
444 status = ISO7816_GetChar(&pAtr[i], &usart_sim);
445 y = pAtr[i++] & 0xF0;
446 }
447 else {
448 y = 0;
449 }
450 }
451 if (status != 0) {
452 return status;
453 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100454
Kévin Redon33d1eb72018-07-08 13:58:12 +0200455 /* Historical Bytes */
456 y = pAtr[1] & 0x0F;
457 for( j=0; (j < y) && (status == 0); j++ ) {
458 status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
459 }
Christina Quast73c2b642015-04-07 13:49:26 +0200460
Kévin Redon33d1eb72018-07-08 13:58:12 +0200461 if (status != 0) {
462 return status;
463 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100464
Kévin Redon33d1eb72018-07-08 13:58:12 +0200465 *pLength = i;
466 return status;
Christina Quast32a90ac2015-03-10 16:18:16 +0100467}
468
469/**
470 * Set data rate and clock frequency
471 * \param dwClockFrequency ICC clock frequency in KHz.
472 * \param dwDataRate ICC data rate in bpd
473 */
474void ISO7816_SetDataRateandClockFrequency( uint32_t dwClockFrequency, uint32_t dwDataRate )
475{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200476 uint8_t ClockFrequency;
Christina Quast32a90ac2015-03-10 16:18:16 +0100477
Kévin Redon33d1eb72018-07-08 13:58:12 +0200478 /* Define the baud rate divisor register */
479 /* CD = MCK / SCK */
480 /* SCK = FIDI x BAUD = 372 x 9600 */
481 /* BOARD_MCK */
482 /* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */
483 USART_SIM->US_BRGR = BOARD_MCK / (dwClockFrequency*1000);
Christina Quast32a90ac2015-03-10 16:18:16 +0100484
Kévin Redon33d1eb72018-07-08 13:58:12 +0200485 ClockFrequency = BOARD_MCK / USART_SIM->US_BRGR;
Christina Quast32a90ac2015-03-10 16:18:16 +0100486
Kévin Redon33d1eb72018-07-08 13:58:12 +0200487 USART_SIM->US_FIDI = (ClockFrequency)/dwDataRate;
Christina Quast32a90ac2015-03-10 16:18:16 +0100488
489}
490
491/**
492 * Pin status for ISO7816 RESET
493 * \return 1 if the Pin RstMC is high; otherwise 0.
494 */
495uint8_t ISO7816_StatusReset( void )
496{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200497 if (st_pinIso7816RstMC) {
498 return PIO_Get(st_pinIso7816RstMC);
499 }
500 return 0;
Christina Quast32a90ac2015-03-10 16:18:16 +0100501}
502
503/**
504 * cold reset
505 */
506void ISO7816_cold_reset( void )
507{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200508 volatile uint32_t i;
Christina Quast32a90ac2015-03-10 16:18:16 +0100509
Kévin Redon33d1eb72018-07-08 13:58:12 +0200510 /* tb: wait ??? cycles*/
511 for( i=0; i<(400*(BOARD_MCK/1000000)); i++ ) {
512 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100513
Kévin Redon33d1eb72018-07-08 13:58:12 +0200514 USART_SIM->US_RHR;
515 USART_SIM->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
Christina Quast32a90ac2015-03-10 16:18:16 +0100516
Kévin Redon33d1eb72018-07-08 13:58:12 +0200517 ISO7816_IccPowerOn();
Christina Quast32a90ac2015-03-10 16:18:16 +0100518}
519
520/**
521 * Warm reset
522 */
523void ISO7816_warm_reset( void )
524{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200525 volatile uint32_t i;
Christina Quast32a90ac2015-03-10 16:18:16 +0100526
527// Clears Reset
Kévin Redon33d1eb72018-07-08 13:58:12 +0200528 ISO7816_IccPowerOff();
Christina Quast32a90ac2015-03-10 16:18:16 +0100529
Kévin Redon33d1eb72018-07-08 13:58:12 +0200530 /* tb: wait ??? cycles */
531 for( i=0; i<(400*(BOARD_MCK/1000000)); i++ ) {
532 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100533
Kévin Redon33d1eb72018-07-08 13:58:12 +0200534 USART_SIM->US_RHR;
535 USART_SIM->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
Christina Quast32a90ac2015-03-10 16:18:16 +0100536
537// Sets Reset
Kévin Redon33d1eb72018-07-08 13:58:12 +0200538 ISO7816_IccPowerOn();
Christina Quast32a90ac2015-03-10 16:18:16 +0100539}
540
541/**
542 * Decode ATR trace
543 * \param pAtr pointer on ATR buffer
544 */
545void ISO7816_Decode_ATR( uint8_t* pAtr )
546{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200547 uint32_t i;
548 uint32_t j;
549 uint32_t y;
550 uint8_t offset;
Christina Quast32a90ac2015-03-10 16:18:16 +0100551
Kévin Redon33d1eb72018-07-08 13:58:12 +0200552 printf("\n\r");
553 printf("ATR: Answer To Reset:\n\r");
554 printf("TS = 0x%X Initial character ",pAtr[0]);
555 if( pAtr[0] == 0x3B ) {
Christina Quast32a90ac2015-03-10 16:18:16 +0100556
Kévin Redon33d1eb72018-07-08 13:58:12 +0200557 printf("Direct Convention\n\r");
558 }
559 else {
560 if( pAtr[0] == 0x3F ) {
Christina Quast32a90ac2015-03-10 16:18:16 +0100561
Kévin Redon33d1eb72018-07-08 13:58:12 +0200562 printf("Inverse Convention\n\r");
563 }
564 else {
565 printf("BAD Convention\n\r");
566 }
567 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100568
Kévin Redon33d1eb72018-07-08 13:58:12 +0200569 printf("T0 = 0x%X Format caracter\n\r",pAtr[1]);
570 printf(" Number of historical bytes: K = %d\n\r", pAtr[1]&0x0F);
571 printf(" Presence further interface byte:\n\r");
572 if( pAtr[1]&0x80 ) {
573 printf("TA ");
574 }
575 if( pAtr[1]&0x40 ) {
576 printf("TB ");
577 }
578 if( pAtr[1]&0x20 ) {
579 printf("TC ");
580 }
581 if( pAtr[1]&0x10 ) {
582 printf("TD ");
583 }
584 if( pAtr[1] != 0 ) {
585 printf(" present\n\r");
586 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100587
Kévin Redon33d1eb72018-07-08 13:58:12 +0200588 i = 2;
589 y = pAtr[1] & 0xF0;
Christina Quast32a90ac2015-03-10 16:18:16 +0100590
Kévin Redon33d1eb72018-07-08 13:58:12 +0200591 /* Read ATR Ti */
592 offset = 1;
593 while (y) {
Christina Quast32a90ac2015-03-10 16:18:16 +0100594
Kévin Redon33d1eb72018-07-08 13:58:12 +0200595 if (y & 0x10) { /* TA[i] */
596 printf("TA[%d] = 0x%X ", offset, pAtr[i]);
597 if( offset == 1 ) {
598 printf("FI = %d ", (pAtr[i]>>8));
599 printf("DI = %d", (pAtr[i]&0x0F));
600 }
601 printf("\n\r");
602 i++;
603 }
604 if (y & 0x20) { /* TB[i] */
605 printf("TB[%d] = 0x%X\n\r", offset, pAtr[i]);
606 i++;
607 }
608 if (y & 0x40) { /* TC[i] */
609 printf("TC[%d] = 0x%X ", offset, pAtr[i]);
610 if( offset == 1 ) {
611 printf("Extra Guard Time: N = %d", pAtr[i]);
612 }
613 printf("\n\r");
614 i++;
615 }
616 if (y & 0x80) { /* TD[i] */
617 printf("TD[%d] = 0x%X\n\r", offset, pAtr[i]);
618 y = pAtr[i++] & 0xF0;
619 }
620 else {
621 y = 0;
622 }
623 offset++;
624 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100625
Kévin Redon33d1eb72018-07-08 13:58:12 +0200626 /* Historical Bytes */
627 printf("Historical bytes:\n\r");
628 y = pAtr[1] & 0x0F;
629 for( j=0; j < y; j++ ) {
630 printf(" 0x%X", pAtr[i]);
631 i++;
632 }
633 printf("\n\r\n\r");
Christina Quast32a90ac2015-03-10 16:18:16 +0100634
635}
636
Christina Quaste24b9ac2015-04-10 17:44:49 +0200637void ISO7816_Set_Reset_Pin(const Pin *pPinIso7816RstMC) {
Kévin Redon33d1eb72018-07-08 13:58:12 +0200638 /* Pin ISO7816 initialize */
639 st_pinIso7816RstMC = (Pin *)pPinIso7816RstMC;
Christina Quaste24b9ac2015-04-10 17:44:49 +0200640}
641
Christina Quast32a90ac2015-03-10 16:18:16 +0100642/** Initializes a ISO driver
643 * \param pPinIso7816RstMC Pin ISO 7816 Rst MC
644 */
Christina Quaste24b9ac2015-04-10 17:44:49 +0200645void ISO7816_Init( Usart_info *usart, bool master_clock )
Christina Quast32a90ac2015-03-10 16:18:16 +0100646{
Kévin Redon33d1eb72018-07-08 13:58:12 +0200647 uint32_t clk;
648 TRACE_DEBUG("ISO_Init\n\r");
Christina Quast32a90ac2015-03-10 16:18:16 +0100649
Kévin Redon33d1eb72018-07-08 13:58:12 +0200650 Usart *us_base = usart->base;
651 uint32_t us_id = usart->id;
Christina Quast32a90ac2015-03-10 16:18:16 +0100652
Kévin Redon33d1eb72018-07-08 13:58:12 +0200653 if (master_clock == true) {
654 clk = US_MR_USCLKS_MCK;
655 } else {
656 clk = US_MR_USCLKS_SCK;
657 }
Christina Quast3eab56e2015-04-10 15:38:49 +0200658
Kévin Redon33d1eb72018-07-08 13:58:12 +0200659 USART_Configure( us_base,
660 US_MR_USART_MODE_IS07816_T_0
661 | clk
662 | US_MR_NBSTOP_1_BIT
663 | US_MR_PAR_EVEN
664 | US_MR_CHRL_8_BIT
665 | US_MR_CLKO
666 | US_MR_INACK /* Inhibit errors */
667 | (3<<24), /* MAX_ITERATION */
668 1,
669 0);
Christina Quast32a90ac2015-03-10 16:18:16 +0100670
Kévin Redon33d1eb72018-07-08 13:58:12 +0200671 /* Disable interrupts */
672 us_base->US_IDR = (uint32_t) -1;
Christina Quast32a90ac2015-03-10 16:18:16 +0100673
Kévin Redon33d1eb72018-07-08 13:58:12 +0200674 /* Configure USART */
675 PMC_EnablePeripheral(us_id);
Christina Quast68cc8592015-04-16 11:08:32 +0200676
Kévin Redon33d1eb72018-07-08 13:58:12 +0200677 us_base->US_FIDI = 372; /* by default */
678 /* Define the baud rate divisor register */
679 /* CD = MCK / SCK */
680 /* SCK = FIDI x BAUD = 372 x 9600 */
681 /* BOARD_MCK */
682 /* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */
683 if (master_clock == true) {
684 us_base->US_BRGR = BOARD_MCK / (372*9600);
685 } else {
686 us_base->US_BRGR = US_BRGR_CD(1);
687 }
Christina Quast32a90ac2015-03-10 16:18:16 +0100688}
689