The Smart Card Detective (SCD)
|
00001 00037 #include <avr/interrupt.h> 00038 #include <avr/io.h> 00039 #include <avr/wdt.h> 00040 #include <util/delay.h> 00041 00042 #include "scd_hal.h" 00043 #include "scd_io.h" 00044 #include "scd_values.h" 00045 #include "utils.h" 00046 00047 #define DEBUG 1 // Set this to 1 to enable debug code 00048 00049 /* Global Variables */ 00050 volatile uint32_t syncCounter; // counter updated regularly, e.g. by timer 2 00051 00052 /* SCD to Terminal functions */ 00053 00054 00063 void EnableTerminalResetInterrupt() 00064 { 00065 EIMSK &= ~(_BV(INT0)); 00066 EICRA |= _BV(ISC01); 00067 EICRA &= ~(_BV(ISC00)); 00068 EIFR |= _BV(INTF0); 00069 EIMSK |= _BV(INT0); 00070 } 00071 00076 void DisableTerminalResetInterrupt() 00077 { 00078 EIMSK &= ~(_BV(INT0)); 00079 } 00080 00088 uint8_t GetTerminalIOLine() 00089 { 00090 return bit_is_set(PINC, PC4); 00091 } 00092 00098 uint8_t GetTerminalResetLine() 00099 { 00100 return bit_is_set(PIND, PD0); 00101 } 00102 00115 void EnableWDT(uint16_t ms) 00116 { 00117 if(ms <= 15) 00118 wdt_enable(WDTO_15MS); 00119 else if(ms <= 30) 00120 wdt_enable(WDTO_30MS); 00121 else if(ms <= 60) 00122 wdt_enable(WDTO_60MS); 00123 else if(ms <= 120) 00124 wdt_enable(WDTO_120MS); 00125 else if(ms <= 250) 00126 wdt_enable(WDTO_250MS); 00127 else if(ms <= 500) 00128 wdt_enable(WDTO_500MS); 00129 else if(ms <= 1000) 00130 wdt_enable(WDTO_1S); 00131 else if(ms <= 2000) 00132 wdt_enable(WDTO_2S); 00133 else if(ms <= 4000) 00134 wdt_enable(WDTO_4S); 00135 else 00136 wdt_enable(WDTO_8S); 00137 00138 WDTCSR |= _BV(WDIE); 00139 } 00140 00144 void DisableWDT() 00145 { 00146 wdt_disable(); 00147 WDTCSR &= ~(_BV(WDIE)); 00148 } 00149 00153 void ResetWDT() 00154 { 00155 wdt_reset(); 00156 } 00157 00167 uint8_t WaitTerminalResetIOLow(uint32_t max_wait) 00168 { 00169 volatile uint8_t tio, treset; 00170 uint8_t result = 0; 00171 uint32_t cnt = 0; 00172 00173 do{ 00174 cnt = cnt + 1; 00175 tio = bit_is_clear(PINC, PC4); 00176 treset = bit_is_clear(PIND, PD0); 00177 result = (tio << 1) | treset; 00178 00179 if(max_wait != 0 && cnt == max_wait) 00180 break; 00181 }while(result == 0); 00182 00183 return result; 00184 } 00185 00191 uint16_t IsTerminalClock() 00192 { 00193 uint8_t sreg; 00194 uint16_t time, result; 00195 00196 sreg = SREG; 00197 cli(); 00198 TCNT3 = 1; // We need to be sure it will not restart in the process 00199 asm volatile("nop\n\t" 00200 "nop\n\t" 00201 "nop\n\t" 00202 "nop\n\t" 00203 "nop\n\t" 00204 "nop\n\t" 00205 "nop\n\t" 00206 "nop\n\t" 00207 "nop\n\t" 00208 "nop\n\t" 00209 "nop\n\t" 00210 "nop\n\t" 00211 "nop\n\t" 00212 "nop\n\t" 00213 "nop\n\t" 00214 "nop\n\t" 00215 "nop\n\t" 00216 "nop\n\t" 00217 "nop\n\t" 00218 "nop\n\t" 00219 ::); 00220 time = TCNT3; 00221 result = time - 1; 00222 SREG = sreg; 00223 00224 return result; 00225 } 00226 00232 uint16_t GetTerminalFreq() 00233 { 00234 uint8_t sreg; 00235 uint16_t time, result; 00236 00237 sreg = SREG; 00238 cli(); 00239 TCNT3 = 1; // We need to be sure it will not restart in the process 00240 asm volatile("nop\n\t" 00241 "nop\n\t" 00242 "nop\n\t" 00243 "nop\n\t" 00244 "nop\n\t" 00245 "nop\n\t" 00246 "nop\n\t" 00247 "nop\n\t" 00248 "nop\n\t" 00249 "nop\n\t" 00250 "nop\n\t" 00251 "nop\n\t" 00252 "nop\n\t" 00253 "nop\n\t" 00254 "nop\n\t" 00255 "nop\n\t" 00256 "nop\n\t" 00257 "nop\n\t" 00258 "nop\n\t" 00259 "nop\n\t" 00260 "nop\n\t" 00261 "nop\n\t" 00262 "nop\n\t" 00263 "nop\n\t" 00264 "nop\n\t" 00265 "nop\n\t" 00266 "nop\n\t" 00267 "nop\n\t" 00268 "nop\n\t" 00269 "nop\n\t" 00270 "nop\n\t" 00271 "nop\n\t" 00272 "nop\n\t" 00273 "nop\n\t" 00274 "nop\n\t" 00275 "nop\n\t" 00276 "nop\n\t" 00277 "nop\n\t" 00278 "nop\n\t" 00279 "nop\n\t" 00280 "nop\n\t" 00281 "nop\n\t" 00282 "nop\n\t" 00283 "nop\n\t" 00284 "nop\n\t" 00285 "nop\n\t" 00286 "nop\n\t" 00287 "nop\n\t" 00288 "nop\n\t" 00289 ::); 00290 time = TCNT3; 00291 00292 if(time == 1) 00293 result = 0; 00294 else 00295 result = (uint16_t)(((F_CPU/1000) * time) / 50); 00296 00297 SREG = sreg; 00298 00299 return result; 00300 } 00301 00309 uint8_t ReadTimerT2() 00310 { 00311 return TCNT2; 00312 } 00313 00314 00322 void StartTimerT2() 00323 { 00324 // We use this to generate an interrupt with the given frequency 00325 OCR2A = 16; // interrupt every 16 timer clocks 00326 TIMSK2 |= _BV(OCIE2A); 00327 00328 TCNT2 = 0; 00329 TCCR2A = _BV(WGM21); // CTC mode, No toggle on OC2X pins, no PWM 00330 TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); // F_CLK_T2 = F_CLK_IO / 1024 00331 } 00332 00336 void StopTimerT2() 00337 { 00338 TCCR2B = 0; 00339 TCCR2A = 0; 00340 TIMSK2 = 0; 00341 OCR2A = 0; 00342 } 00343 00351 //void IncrementCounter() 00352 //{ 00353 // syncCounter++; 00354 //} 00355 00362 //uint32_t GetCounter() 00363 //{ 00364 // return syncCounter; 00365 //} 00366 00372 //void ResetCounter() 00373 //{ 00374 // syncCounter = 0; 00375 //} 00376 00380 uint16_t ReadCounterTerminal() 00381 { 00382 uint16_t i; 00383 uint8_t sreg; 00384 00385 // do the reading (16-bit via 2 x 8-bit reads) with interrupts disabled 00386 sreg = SREG; 00387 cli(); 00388 i = TCNT3; 00389 SREG = sreg; 00390 00391 return i; 00392 00393 //or just: return Read16bitRegister(&TCNT3); but it might add more code 00394 } 00395 00396 00404 void StartCounterTerminal() 00405 { 00406 //TCCR3A = 0; // No toggle on OC3X pins 00407 TCCR3A = 0x0C; // set OC3C to 1 on compare match 00408 // This is needed because by some misterious hardware bug (i.e. not 00409 // as in the specs) the OC3C line (I/O for terminal) is changed 00410 // even if TCCR3A = 0 00411 00412 Write16bitRegister(&OCR3A, ETU_TERMINAL); 00413 TCCR3B = 0x0F; // CTC, timer external source 00414 } 00415 00419 void StopCounterTerminal() 00420 { 00421 TCCR3B = 0; 00422 Write16bitRegister(&TCNT3, 0); //TCNT3 = 0; 00423 } 00424 00428 void PauseCounterTerminal() 00429 { 00430 TCCR3B = 0; 00431 } 00432 00440 void LoopTerminalETU(uint8_t nEtus) 00441 { 00442 uint8_t i; 00443 00444 Write16bitRegister(&OCR3A, ETU_TERMINAL); // set ETU 00445 TCCR3A = 0x0C; // set OC3C to 1 00446 Write16bitRegister(&TCNT3, 1); // TCNT3 = 1 00447 TIFR3 |= _BV(OCF3A); // Reset OCR3A compare flag 00448 00449 for(i = 0; i < nEtus; i++) 00450 { 00451 while(bit_is_clear(TIFR3, OCF3A)); 00452 TIFR3 |= _BV(OCF3A); 00453 } 00454 } 00455 00456 00466 void SendByteTerminalNoParity(uint8_t byte, uint8_t inverse_convention) 00467 { 00468 uint8_t bitval, i, parity; 00469 volatile uint8_t tmp; 00470 00471 // check we have clock from terminal to avoid damage 00472 // assuming the counter is started 00473 if(!GetTerminalFreq()) 00474 return; 00475 00476 // this code is needed to be sure that the I/O line will not 00477 // toggle to low when we set DDRC4 as output 00478 TCCR3A = 0x0C; // Set OC3C on compare 00479 00480 PORTC |= _BV(PC4); // Put to high 00481 DDRC |= _BV(PC4); // Set PC4 (OC3C) as output 00482 Write16bitRegister(&OCR3A, ETU_TERMINAL); // set ETU 00483 Write16bitRegister(&TCNT3, 1); // TCNT3 = 1 00484 TIFR3 |= _BV(OCF3A); // Reset OCR3A compare flag 00485 00486 // send each bit using OC3C (connected to the terminal I/O line) 00487 // each TCCR3A value will be visible after the next compare match 00488 00489 // start bit 00490 TCCR3A = 0x08; 00491 00492 // while sending the start bit convert the byte if necessary 00493 // to match inverse conversion 00494 if(inverse_convention) 00495 { 00496 tmp = ~byte; 00497 byte = 0; 00498 for(i = 0; i < 8; i++) 00499 { 00500 bitval = tmp & _BV((7-i)); 00501 if(bitval) byte = byte | _BV(i); 00502 } 00503 } 00504 00505 00506 while(bit_is_clear(TIFR3, OCF3A)); 00507 TIFR3 |= _BV(OCF3A); 00508 00509 // byte value 00510 parity = 0; 00511 for(i = 0; i < 8; i++) 00512 { 00513 bitval = (uint8_t) (byte & (uint8_t)(1 << i)); 00514 00515 if(bitval != 0) 00516 { 00517 TCCR3A = 0x0C; 00518 if(!inverse_convention) parity = parity ^ 1; 00519 } 00520 else 00521 { 00522 TCCR3A = 0x08; 00523 if(inverse_convention) parity = parity ^ 1; 00524 } 00525 00526 while(bit_is_clear(TIFR3, OCF3A)); 00527 TIFR3 |= _BV(OCF3A); 00528 } 00529 00530 // parity bit 00531 if((!inverse_convention && parity != 0) || 00532 (inverse_convention && parity == 0)) 00533 TCCR3A = 0x0C; 00534 else 00535 TCCR3A = 0x08; 00536 00537 // wait for the last bit to be sent (need to toggle and 00538 // keep for ETU_TERMINAL clocks) 00539 while(bit_is_clear(TIFR3, OCF3A)); 00540 TIFR3 |= _BV(OCF3A); 00541 while(bit_is_clear(TIFR3, OCF3A)); 00542 TIFR3 |= _BV(OCF3A); 00543 00544 // reset OC3C and put I/O to high (input) 00545 TCCR3A = 0x0C; // set OC3C to 1 00546 DDRC &= ~(_BV(PC4)); 00547 PORTC |= _BV(PC4); 00548 } 00549 00560 uint8_t SendByteTerminalParity(uint8_t byte, uint8_t inverse_convention) 00561 { 00562 uint8_t i; 00563 volatile uint8_t tmp; 00564 00565 SendByteTerminalNoParity(byte, inverse_convention); 00566 00567 // wait for one ETU to read I/O line 00568 LoopTerminalETU(1); 00569 00570 // if there is a parity error try 4 times to resend 00571 if(bit_is_clear(PINC, PC4)) 00572 { 00573 Write16bitRegister(&OCR3A, ETU_TERMINAL); // set ETU 00574 Write16bitRegister(&TCNT3, 1); // TCNT3 = 1 00575 TIFR3 |= _BV(OCF3A); // Reset OCR3A compare flag 00576 TCCR3A = 0x0C; // set OC3C to 1 00577 i = 0; 00578 00579 do{ 00580 i++; 00581 00582 // wait 2 ETUs before resending 00583 LoopTerminalETU(2); 00584 00585 SendByteTerminalNoParity(byte, inverse_convention); 00586 00587 // wait for one ETU and read I/O line 00588 LoopTerminalETU(1); 00589 tmp = bit_is_clear(PINC, PC4); 00590 }while(i<4 && tmp != 0); 00591 00592 if(tmp != 0) 00593 return 1; 00594 } 00595 00596 return 0; 00597 } 00598 00605 uint8_t WaitForTerminalData(uint16_t max_cycles) 00606 { 00607 uint8_t result = 0; 00608 uint16_t c = 0; 00609 volatile uint8_t bit; 00610 00611 do{ 00612 bit = bit_is_set(PINC, PC4); 00613 c = c + 1; 00614 00615 if(max_cycles != 0 && c == max_cycles) break; 00616 }while(bit != 0); 00617 00618 00619 if(bit != 0) result = 1; 00620 00621 return result; 00622 } 00623 00624 00640 uint8_t GetByteTerminalNoParity( 00641 uint8_t inverse_convention, 00642 uint8_t *r_byte, 00643 uint32_t max_wait) 00644 { 00645 volatile uint8_t bit; 00646 volatile uint8_t tio, treset; 00647 uint8_t i, byte, parity; 00648 uint32_t cnt; 00649 00650 TCCR3A = 0x0C; // set OC3C because of chip behavior 00651 DDRC &= ~(_BV(PC4)); // Set PC4 (OC3C) as input 00652 PORTC |= _BV(PC4); // enable pull-up 00653 00654 // wait for reset or start bit 00655 cnt = 0; 00656 while(1) 00657 { 00658 cnt = cnt + 1; 00659 00660 // check we have clock from terminal 00661 if(!IsTerminalClock()) 00662 return RET_TERMINAL_NO_CLOCK; 00663 00664 // check for terminal reset (reset low) 00665 treset = bit_is_clear(PIND, PD0); 00666 if(treset) 00667 return RET_TERMINAL_RESET_LOW; 00668 00669 // check for start bit (Terminal I/O low) 00670 tio = bit_is_clear(PINC, PC4); 00671 if(tio) 00672 break; 00673 00674 if(max_wait != 0 && cnt == max_wait) 00675 return RET_TERMINAL_TIME_OUT; 00676 } 00677 00678 Write16bitRegister(&TCNT3, 1); // TCNT3 = 1 00679 Write16bitRegister(&OCR3A, ETU_HALF(ETU_TERMINAL)); // OCR3A approx. 0.5 ETU 00680 TIFR3 |= _BV(OCF3A); // Reset OCR3A compare flag 00681 00682 // Wait until the timer/counter 3 reaches the value in OCR3A 00683 while(bit_is_clear(TIFR3, OCF3A)); 00684 TIFR3 |= _BV(OCF3A); 00685 00686 // check result and set timer for next bit 00687 bit = bit_is_set(PINC, PC4); 00688 Write16bitRegister(&OCR3A, ETU_TERMINAL); // OCR3A = 1 ETU => next bit at 1.5 ETU 00689 *r_byte = 0; 00690 byte = 0; 00691 parity = 0; 00692 if(bit) return 1; 00693 00694 // read the byte in correct conversion mode 00695 for(i = 0; i < 8; i++) 00696 { 00697 while(bit_is_clear(TIFR3, OCF3A)); 00698 TIFR3 |= _BV(OCF3A); 00699 bit = bit_is_set(PINC, PC4); 00700 00701 if(inverse_convention && bit == 0) 00702 { 00703 byte = byte | _BV(7-i); 00704 parity = parity ^ 1; 00705 } 00706 else if(inverse_convention == 0 && bit != 0) 00707 { 00708 byte = byte | _BV(i); 00709 parity = parity ^ 1; 00710 } 00711 } 00712 00713 *r_byte = byte; 00714 00715 00716 // read the parity bit 00717 while(bit_is_clear(TIFR3, OCF3A)); 00718 TIFR3 |= _BV(OCF3A); 00719 bit = bit_is_set(PINC, PC4); 00720 00721 // wait 0.5 ETUs to for parity bit to be completely received 00722 //Write16bitRegister(&OCR3A, 186); 00723 Write16bitRegister(&OCR3A, ETU_HALF(ETU_TERMINAL)); 00724 while(bit_is_clear(TIFR3, OCF3A)); 00725 TIFR3 |= _BV(OCF3A); 00726 00727 if(inverse_convention) 00728 { 00729 if(parity && bit) return 1; 00730 if(!parity && !bit) return 1; 00731 } 00732 else 00733 { 00734 if(parity && !bit) return 1; 00735 if(!parity && bit) return 1; 00736 } 00737 00738 return 0; 00739 } 00740 00755 uint8_t GetByteTerminalParity( 00756 uint8_t inverse_convention, 00757 uint8_t *r_byte, 00758 uint32_t max_wait) 00759 { 00760 uint8_t result; 00761 00762 result = GetByteTerminalNoParity(inverse_convention, r_byte, max_wait); 00763 if(result == RET_ERROR) 00764 { 00765 // check we have clock from terminal to avoid damage 00766 if(!GetTerminalFreq()) 00767 return result; 00768 00769 // set I/O low for at least 1 ETU starting at 10.5 ETU from start bit 00770 TCCR3A = 0x0C; // OC3C set to 1 on compare 00771 DDRC |= _BV(PC4); // Set PC4 (OC3C) as output 00772 //Write16bitRegister(&OCR3A, 170); // OCR3A ~= 0.5 ETU 00773 Write16bitRegister(&OCR3A, 00774 ETU_LESS_THAN_HALF(ETU_TERMINAL)); // OCR3A ~= 0.5 ETU 00775 Write16bitRegister(&TCNT3, 1); // TCNT3 = 1 00776 TIFR3 |= _BV(OCF3A); // Reset OCR3A compare flag 00777 00778 TCCR3A = 0x08; // OC3C toggles to low on compare 00779 00780 while(bit_is_clear(TIFR3, OCF3A)); 00781 TIFR3 |= _BV(OCF3A); 00782 //Write16bitRegister(&OCR3A, 400); // OCR3A > 1 ETU 00783 Write16bitRegister(&OCR3A, 00784 ETU_EXTENDED(ETU_TERMINAL)); // OCR3A > 1 ETU 00785 while(bit_is_clear(TIFR3, OCF3A)); 00786 TIFR3 |= _BV(OCF3A); 00787 00788 // set I/O to high (input) 00789 TCCR3A = 0x0C; 00790 DDRC &= ~(_BV(PC4)); 00791 PORTC |= _BV(PC4); 00792 00793 // wait for the last ETU to complete 00794 //Write16bitRegister(&OCR3A, 158); 00795 Write16bitRegister(&OCR3A, ETU_LESS_THAN_HALF(ETU_TERMINAL)); 00796 while(bit_is_clear(TIFR3, OCF3A)); 00797 TIFR3 |= _BV(OCF3A); 00798 } 00799 00800 return result; 00801 } 00802 00803 /* SCD to ICC functions */ 00804 00808 uint8_t IsICCInserted() 00809 { 00810 #ifdef INVERT_ICC_SWITCH 00811 return bit_is_clear(PIND, PD1); 00812 #else 00813 return bit_is_set(PIND, PD1); 00814 #endif 00815 } 00816 00817 00821 uint8_t IsICCPowered() 00822 { 00823 return bit_is_clear(PIND, PD7); 00824 } 00825 00831 uint8_t PowerUpICC() 00832 { 00833 if(!IsICCInserted()) 00834 return 1; 00835 00836 PORTD &= ~(_BV(PD7)); 00837 DDRD |= _BV(PD7); 00838 00839 return 0; 00840 } 00841 00845 void PowerDownICC() 00846 { 00847 DDRD |= _BV(PD7); 00848 PORTD |= _BV(PD7); 00849 } 00850 00851 00859 void LoopICCETU(uint8_t nEtus) 00860 { 00861 uint8_t i; 00862 00863 Write16bitRegister(&OCR1A, ETU_ICC); // set ETU 00864 TCCR1A = 0x30; // set OC1B to 1 on compare match 00865 Write16bitRegister(&TCNT1, 1); // TCNT1 = 1 00866 TIFR1 |= _BV(OCF1A); // Reset OCR1A compare flag 00867 00868 for(i = 0; i < nEtus; i++) 00869 { 00870 while(bit_is_clear(TIFR1, OCF1A)); 00871 TIFR1 |= _BV(OCF1A); 00872 } 00873 } 00874 00882 uint8_t WaitForICCData(uint32_t max_cycles) 00883 { 00884 uint8_t result = 0; 00885 uint32_t c = 0; 00886 volatile uint8_t bit; 00887 00888 do{ 00889 bit = bit_is_set(PINB, PB6); 00890 c = c + 1; 00891 00892 if(max_cycles != 0 && c == max_cycles) break; 00893 }while(bit != 0); 00894 00895 00896 if(bit != 0) result = 1; 00897 00898 return result; 00899 } 00900 00911 uint8_t GetByteICCNoParity(uint8_t inverse_convention, uint8_t *r_byte) 00912 { 00913 volatile uint8_t bit; 00914 uint8_t i, byte, parity; 00915 00916 TCCR1A = 0x30; // set OC1B to 1 on compare match 00917 DDRB &= ~(_BV(PB6)); // Set I/O (PB6) to reception mode 00918 00919 #if PULL_UP_HIZ_ICC 00920 PORTB |= _BV(PB6); 00921 #else 00922 PORTB &= ~(_BV(PB6)); 00923 #endif 00924 00925 // wait for start bit 00926 while(bit_is_set(PINB, PB6)); 00927 00928 Write16bitRegister(&TCNT1, 1); // TCNT1 = 1 00929 Write16bitRegister(&OCR1A, ETU_HALF(ETU_ICC)); // OCR1A 0.5 ETU 00930 TIFR1 |= _BV(OCF1A); // Reset OCR1A compare flag 00931 00932 while(bit_is_clear(TIFR1, OCF1A)); 00933 TIFR1 |= _BV(OCF1A); 00934 00935 // check result and set timer for next bit 00936 bit = bit_is_set(PINB, PB6); 00937 Write16bitRegister(&OCR1A, ETU_ICC); // OCR1A = 1 ETU => next bit at 1.5 ETU 00938 *r_byte = 0; 00939 byte = 0; 00940 parity = 0; 00941 if(bit) return 1; 00942 00943 // read the byte in correct conversion mode 00944 for(i = 0; i < 8; i++) 00945 { 00946 while(bit_is_clear(TIFR1, OCF1A)); 00947 TIFR1 |= _BV(OCF1A); 00948 bit = bit_is_set(PINB, PB6); 00949 00950 if(inverse_convention && bit == 0) 00951 { 00952 byte = byte | _BV(7-i); 00953 parity = parity ^ 1; 00954 } 00955 else if(inverse_convention == 0 && bit != 0) 00956 { 00957 byte = byte | _BV(i); 00958 parity = parity ^ 1; 00959 } 00960 } 00961 00962 *r_byte = byte; 00963 00964 // read the parity bit 00965 while(bit_is_clear(TIFR1, OCF1A)); 00966 TIFR1 |= _BV(OCF1A); 00967 bit = bit_is_set(PINB, PB6); 00968 00969 // wait 0.5 ETUs to for parity bit to be completely received 00970 Write16bitRegister(&OCR1A, ETU_HALF(ETU_ICC)); 00971 while(bit_is_clear(TIFR1, OCF1A)); 00972 TIFR1 |= _BV(OCF1A); 00973 00974 if(inverse_convention) 00975 { 00976 if(parity && bit) return 1; 00977 if(!parity && !bit) return 1; 00978 } 00979 else 00980 { 00981 if(parity && !bit) return 1; 00982 if(!parity && bit) return 1; 00983 } 00984 00985 return 0; 00986 } 00987 00988 00999 uint8_t GetByteICCParity(uint8_t inverse_convention, uint8_t *r_byte) 01000 { 01001 uint8_t result; 01002 01003 result = GetByteICCNoParity(inverse_convention, r_byte); 01004 if(result != 0) 01005 { 01006 // check the card is still inserted 01007 if(!IsICCInserted()) 01008 return result; 01009 01010 // set I/O low for at least 1 ETU starting at 10.5 ETU from start bit 01011 TCCR1A = 0x30; // set OC1B on compare match 01012 DDRB |= _BV(PB6); // Set PB6 (OC1B) as output 01013 Write16bitRegister(&OCR1A, 01014 ETU_LESS_THAN_HALF(ETU_ICC)); 01015 Write16bitRegister(&TCNT1, 1); 01016 TIFR1 |= _BV(OCF1A); // Reset OCF1A compare flag 01017 TCCR1A = 0x20; // clear OC1B on compare match 01018 01019 while(bit_is_clear(TIFR1, OCF1A)); 01020 TIFR1 |= _BV(OCF1A); 01021 Write16bitRegister(&OCR1A, 01022 ETU_EXTENDED(ETU_ICC)); // OCR1A > 1 ETU 01023 while(bit_is_clear(TIFR1, OCF1A)); 01024 TIFR1 |= _BV(OCF1A); 01025 01026 // set I/O to high (input) 01027 TCCR1A = 0x30; 01028 DDRB &= ~(_BV(PB6)); 01029 PORTB |= _BV(PB6); 01030 01031 // wait for the last ETU to complete 01032 Write16bitRegister(&OCR1A, ETU_LESS_THAN_HALF(ETU_ICC)); 01033 while(bit_is_clear(TIFR1, OCF1A)); 01034 TIFR1 |= _BV(OCF1A); 01035 } 01036 01037 return result; 01038 } 01039 01048 void SendByteICCNoParity(uint8_t byte, uint8_t inverse_convention) 01049 { 01050 uint8_t bitval, i, parity; 01051 volatile uint8_t tmp; 01052 01053 if(!IsICCInserted()) 01054 return; 01055 01056 // this code is needed to be sure that the I/O line will not 01057 // toggle to low when we set DDRB6 as output 01058 TCCR1A = 0x30; // Set OC1B on compare 01059 PORTB |= _BV(PB6); // Put to high 01060 DDRB |= _BV(PB6); // Set PB6 (OC1B) as output 01061 Write16bitRegister(&OCR1A, ETU_ICC); 01062 Write16bitRegister(&TCNT1, 1); 01063 TIFR1 |= _BV(OCF1A); // Reset OCF1A compare flag 01064 01065 // send each bit using OC1B (connected to the ICC I/O line) 01066 // each TCCR1A value will be visible after the next compare match 01067 01068 // start bit 01069 TCCR1A = 0x20; 01070 01071 // while sending the start bit convert the byte if necessary 01072 // to match inverse conversion 01073 if(inverse_convention) 01074 { 01075 tmp = ~byte; 01076 byte = 0; 01077 for(i = 0; i < 8; i++) 01078 { 01079 bitval = tmp & _BV((7-i)); 01080 if(bitval) byte = byte | _BV(i); 01081 } 01082 } 01083 01084 01085 while(bit_is_clear(TIFR1, OCF1A)); 01086 TIFR1 |= _BV(OCF1A); 01087 01088 // byte value 01089 parity = 0; 01090 for(i = 0; i < 8; i++) 01091 { 01092 bitval = (uint8_t) (byte & (uint8_t)(1 << i)); 01093 01094 if(bitval != 0) 01095 { 01096 TCCR1A = 0x30; 01097 if(!inverse_convention) parity = parity ^ 1; 01098 } 01099 else 01100 { 01101 TCCR1A = 0x20; 01102 if(inverse_convention) parity = parity ^ 1; 01103 } 01104 01105 while(bit_is_clear(TIFR1, OCF1A)); 01106 TIFR1 |= _BV(OCF1A); 01107 } 01108 01109 // parity bit 01110 if((!inverse_convention && parity != 0) || 01111 (inverse_convention && parity == 0)) 01112 TCCR1A = 0x30; 01113 else 01114 TCCR1A = 0x20; 01115 01116 // wait for the last bit to be sent (need to toggle and 01117 // keep for ETU_TERMINAL clocks) 01118 while(bit_is_clear(TIFR1, OCF1A)); 01119 TIFR1 |= _BV(OCF1A); 01120 while(bit_is_clear(TIFR1, OCF1A)); 01121 TIFR1 |= _BV(OCF1A); 01122 01123 // reset OC1B and put I/O to high (input) 01124 TCCR1A = 0x30; 01125 DDRB &= ~(_BV(PB6)); 01126 PORTB |= _BV(PB6); 01127 } 01128 01139 uint8_t SendByteICCParity(uint8_t byte, uint8_t inverse_convention) 01140 { 01141 uint8_t i; 01142 volatile uint8_t tmp; 01143 01144 SendByteICCNoParity(byte, inverse_convention); 01145 01146 // wait for one ETU to read I/O line 01147 LoopICCETU(1); 01148 01149 // if there is aparity error try 4 times to resend 01150 if(bit_is_clear(PINB, PB6)) 01151 { 01152 Write16bitRegister(&OCR1A, ETU_ICC); 01153 Write16bitRegister(&TCNT1, 1); 01154 TIFR1 |= _BV(OCF1A); // Reset OCF1A compare flag 01155 TCCR1A = 0x30; // set OC1B to 1 01156 i = 0; 01157 01158 do{ 01159 i++; 01160 01161 // wait 2 ETUs before resending 01162 LoopICCETU(2); 01163 01164 SendByteICCNoParity(byte, inverse_convention); 01165 01166 // wait for one ETU and read I/O line 01167 LoopICCETU(1); 01168 tmp = bit_is_clear(PINB, PB6); 01169 }while(i<4 && tmp != 0); 01170 01171 if(tmp != 0) 01172 return 1; 01173 } 01174 01175 return 0; 01176 } 01177 01178 01185 void SetICCResetLine(uint8_t high) 01186 { 01187 if(high) 01188 PORTD |= _BV(PD4); 01189 else 01190 PORTD &= ~(_BV(PD4)); 01191 } 01192 01200 uint8_t ActivateICC(uint8_t warm) 01201 { 01202 if(warm) 01203 { 01204 // Put RST to low 01205 PORTD &= ~(_BV(PD4)); 01206 DDRD |= _BV(PD4); 01207 } 01208 else{ 01209 // Put I/O, CLK and RST lines to 0 and give VCC 01210 PORTB &= ~(_BV(PB6)); 01211 DDRB |= _BV(PB6); 01212 #if ICC_CLK_OCR0A 01213 PORTB &= ~(_BV(PB7)); 01214 DDRB |= _BV(PB7); 01215 #else 01216 // In the case of an external clock we don't want the MCU to receive input 01217 PORTB &= ~(_BV(PB7)); 01218 DDRB &= ~(_BV(PB7)); 01219 #endif 01220 PORTD &= ~(_BV(PD4)); 01221 DDRD |= _BV(PD4); 01222 _delay_us(ICC_VCC_DELAY_US); 01223 if(PowerUpICC()) 01224 { 01225 DeactivateICC(); 01226 return 1; 01227 } 01228 _delay_us(ICC_VCC_DELAY_US); 01229 } 01230 01231 // Put I/O to reception mode and then give clock if cold reset 01232 DDRB &= ~(_BV(PB6)); // Set I/O to reception mode 01233 #if PULL_UP_HIZ_ICC 01234 PORTB |= _BV(PB6); 01235 #else 01236 PORTB &= ~(_BV(PB6)); 01237 #endif 01238 01239 if(warm == 0) 01240 { 01241 // I use the Timer 0 (8-bit) to give the clock to the ICC 01242 // and the Timer 1 (16-bit) to count the number of clocks 01243 // in order to provide the correct ETU reference 01244 OCR0A = ICC_CLK_OCR0A; // set F_TIMER0 = CLK_IO / (2 * (ICC_CLK_OCR0A + 1)); 01245 TCNT0 = 0; 01246 #if ICC_CLK_OCR0A 01247 TCCR0A = 0x42; // toggle OC0A (PB7) on compare match, CTC mode 01248 TCCR0B = 0x01; // Start timer 0, CLK = CLK_IO 01249 #else 01250 TCCR0A = 0; // Timer 0 not used for external clock 01251 TCCR0B = 0; // Timer 0 not used for external clock 01252 #endif 01253 01254 TCCR1A = 0x30; // set OC1B (PB6) to 1 on compare match 01255 Write16bitRegister(&OCR1A, ETU_ICC);// ETU = 372 * (F_TIMER1 / F_TIMER0) 01256 TCCR1B = ICC_CLK_TCCR1B; // Start timer 1, CTC, CLK based on TCCR1B 01257 TCCR1C = 0x40; // Force compare match on OC1B so that 01258 // we get the I/O line to high 01259 } 01260 01261 return 0; 01262 } 01263 01267 void DeactivateICC() 01268 { 01269 // Set reset to low 01270 PORTD &= ~(_BV(PD4)); 01271 DDRD |= _BV(PD4); 01272 01273 // Stop timers 01274 TCCR0A = 0; 01275 TCCR0B = 0; 01276 TCCR1A = 0; 01277 TCCR1B = 0; 01278 01279 #if ICC_CLK_OCR0A 01280 // Set CLK line to low to be sure 01281 PORTB &= ~(_BV(PB7)); 01282 DDRB |= _BV(PB7); 01283 #endif 01284 01285 // Set I/O line to low 01286 PORTB &= ~(_BV(PB6)); 01287 DDRB |= _BV(PB6); 01288 01289 // Depower VCC 01290 PORTD |= _BV(PD7); 01291 DDRD |= _BV(PD7); 01292 } 01293 01297 void EnableICCInsertInterrupt() 01298 { 01299 EICRA |= _BV(ISC10); 01300 EICRA &= ~(_BV(ISC11)); 01301 EIMSK |= _BV(INT1); 01302 } 01303 01307 void DisableICCInsertInterrupt() 01308 { 01309 EIMSK &= ~(_BV(INT1)); 01310 } 01311