The Smart Card Detective (SCD)
scd_hal.c
Go to the documentation of this file.
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 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines