#include "includes.h"

//************************************************************************
// trochu teorie:
// MIFARE KARTY muzou byt bud 4-byte UID nebo 7-byte UID (UID je zkratka pro ukikatni identifikator)
// 4-byte UID se nazyva SINGLE SIZE UID, 7-byte pak DOUBLE SIZE UID, a existuje i teoreticky TRIPLE SIZE UID (zatim se nepouziva)
//
// TOTO PLATI PRO SINGLE SIZE UID:
// struktura  UID0-UID1-UID2-UID3
// podle prvniho bajtu UID0 se deli na tyto varianty karet:
// UID0=0x08		bajty UID1-UID3 jsou dynamicky generovane po kazdem POR
// UID0=0x.0-0x.7	rezervace MIFARE
// UID0=0x18-0x78	rezervace MIFARE
// UID0=0x98-0xE8	rezervace MIFARE
// UID0=0x.9-0x.E	rezervace MIFARE
// UID0=0x.F		fixni rozsah, neunikatni
// UID0=0x88		kaskadovy tag
// UID0=0xF8		rezerva
//
//************************************************************************
// Identifikace vyrobce:
// single size UID nemaji identifikaci vyrobce karty
// identifikce je v prvnim bajtu UID0
// UID0=0x81-0xFE	nepovoleny rozsah
// UID0=0x04		vyrobce NXP
// UID0=0x37		vyrobce KOVIO

// navratove kody karet:
//************************************************************************
//	VYROBCE		KARTA           ATQA        SAK            
//************************************************************************
/*
  NXP	Mifare_Mini         	0x0400		0x09

		Mifare_One(S70)			0x0200 
		Mifare_Pro(X)			0x0800 
			
  NXP	MIFARE Plus 1k	 0x0400/0x0200		0x08
  NXP 	MIFARE Plus 1k	 0x0400/0x0200		0x10
  NXP 	MIFARE Plus 4k	 0x0400/0x0200		0x18
  NXP 	MIFARE Plus 4k	 0x0400/0x0200		0x11
  NXP	MIFARE Plus 1k/4k		0x0200		0x20
  NXP 	MIFARE Plus 2k/4k		0x4400		0x20

  NXP   Mifare_Classic 1K 		0x0400      0x08
  NXP   Mifare_Classic 4K   	0x0200      0x18
  NXP   Mifare_Ultraligh_CL2   	0x4400      0x00
  NXP   Mifare_Ultraligh_CL1   	0x4400      0x04
  
  NXP   Mifare_DESFire_CL1 		0x4403      0x24
  NXP   Mifare_DESFire_CL2 		0x4403      0x20
  NXP   Mifare_DESFire_ev1_CL1 	0x4403      0x04
  NXP   Mifare_DESFire_ev1_CL2 	0x4403      0x20

    
  NXP   JCOP31					0x0403      0x28
  NXP   JCOP31 v2.4.1		  	0x4800    	0x20
  NXP   JCOP41 v2.2		  		0x4800  	0x20
  NXP   JCOP41 v2.3.1		  	0x0400 	    0x28
	
  INFINEON    Mifare_Classic 1K   0x0400    0x88
  GEMPLUS     MPCOS				  0x0200    0x98
  INNOVISION R&T Jewel			  0x0200	0x98
  NOKIA	MIFARE Classic 4k  		  0x0200	0x38
*/

 


//************************************************************************
// RC500InterfaceInit
//************************************************************************
char RC500InterfaceInit(void)   
 {   
    unsigned char _status = NO_ERROR;   
    unsigned char n;   
    unsigned int i;   

    n = 0xFF;   
    i = 0x2000;   

// touto sekvenci se zajisti RESEt cteciho cipu    
    RC500_RST=0;   
    wait_ms(50);   
    RC500_RST=1;   
    wait_ms(2);   
    RC500_RST=0;   
    wait_ms(2);   
   
   
    while (i!=0 && n)   
    {   
	   ClearWDT();
       n = ReadRawRC(RegCommand);   
       i--;   
    }   
    
    if (i != 0)   
    {   
       WriteRawRC(RegPage,0x80);   
       WriteRawRC(RegPage,0x80); 
	   n = 0x80;   
       while ( (i!=0) && (n&0x80) )   
       {   
	   	   ClearWDT();
           n = ReadRawRC(RegCommand);   
           i--;   
       }   
       if (i==0 || (n&0xFF))   
       {
		 _status = MIFARE_RESET_ERR;
	   }   
    }   
    else   
     {
	   _status = MIFARE_RESET_ERR;
     }   
       
    if (_status == NO_ERROR)   
    {  
 	   WriteRawRC(RegPage,0x0);
    }   
       
    return _status;   
 } 
 

 
/***************************************************************
//   S E T   A   B I T   M A S K 
  * Function Name : SetBitMask
 * Description: Set RC522 register bit
 * Input parameters : reg - register address ; mask - set value
 * Return value: None
***************************************************************/
char SetBitMask(unsigned char reg,unsigned char mask)  
{
   tUChar tmp = 0x0;

   tmp = ReadRawRC(reg)&0xf0;
   WriteRawRC(reg,tmp | mask);  // set bit mask
  
   return 0x0;
}



/***************************************************************
//   C L E A R   A   B I T   M A S K 
 * Function Name : ClearBitMask
 * Description : clear RC522 register bit
 * Input parameters : reg - register address ; mask - clear bit value
 * Return value: None
***************************************************************/
char ClearBitMask(unsigned char reg,unsigned char mask)  
{
   char tmp = 0x0;
   tmp = ReadRawRC(reg);
   WriteRawRC(reg,tmp & ~mask);  // clear bit mask
   return 0x0;
}



/***************************************************************
//   FlushFIFO
***************************************************************/
void FlushFIFO(void)
{  
   SetBitMask(RegControl,0x01);
}


/***************************************************************
         RF ON
****************************************************************/
void MifReaderPowerUp(void)
{
  ClearBitMask(RegControl,0x20);		// POWER UP
}


void MifReaderPowerDown(void)
{
  SetBitMask(RegControl,0x20);			// POWER DOWN
}



//***************************************************************
// PcdAntennaOn()
//***************************************************************
void PcdAntennaOn(void)
{
    unsigned char i;

	i = ReadRawRC(RegTxControl);
    if (!(i & 0x03))							// pokud antena neni jeste zapnuta tak zapnout
     {
       SetBitMask(RegTxControl, 0x03|0x08);		// symetricke buzeni anteny do Tx1+Tx2
     }
}


//***************************************************************
// PcdAntennaOff()
//***************************************************************
void PcdAntennaOff(void)
{
    ClearBitMask(RegTxControl, 0x03|0x08);
}

 
//************************************************************************
// PcdSetTmo
// input:tmolength
//************************************************************************
void PcdSetTmo(unsigned char tmoLength)   
 {   
    switch(tmoLength)   
    {     
       /*case 0:                         	  // (0.302 ms) FWI=0   
          WriteRawRC(RegTimerClock,0x07); // TAutoRestart=0,TPrescale=128   
          WriteRawRC(RegTimerReload,0x21);// TReloadVal = 'h21 =33(dec)    
          break;   
       case 1:                         	  // (0.604 ms) FWI=1   
          WriteRawRC(RegTimerClock,0x07); // TAutoRestart=0,TPrescale=128   
          WriteRawRC(RegTimerReload,0x41);// TReloadVal = 'h41 =65(dec)    
          break;   
       case 2:                         	  // (1.208 ms) FWI=2   
          WriteRawRC(RegTimerClock,0x07); // TAutoRestart=0,TPrescale=128   
          WriteRawRC(RegTimerReload,0x81);// TReloadVal = 'h81 =129(dec)    
          break;   
       case 3:                         	  // (2.416 ms) FWI=3   
          WriteRawRC(RegTimerClock,0x09); // TAutoRestart=0,TPrescale=4*128   
          WriteRawRC(RegTimerReload,0x41);// TReloadVal = 'h41 =65(dec)    
          break;   
		  */
       case 4:                         	  // (4.833 ms) FWI=4   
          WriteRawRC(RegTimerClock,0x09); // TAutoRestart=0,TPrescale=4*128   
          WriteRawRC(RegTimerReload,0x81);// TReloadVal = 'h81 =129(dec)    
          break;   
       case 5:                         	  // (9.666 ms) FWI=5   
          WriteRawRC(RegTimerClock,0x0B); // TAutoRestart=0,TPrescale=16*128   
          WriteRawRC(RegTimerReload,0x41);// TReloadVal = 'h41 =65(dec)    
          break;   
       /*
	   case 6:                         	  // (19.33 ms) FWI=6   
          WriteRawRC(RegTimerClock,0x0B); // TAutoRestart=0,TPrescale=16*128   
          WriteRawRC(RegTimerReload,0x81);// TReloadVal = 'h81 =129(dec)    
          break;   
       case 7:                         	  // (38.66 ms) FWI=7   
          WriteRawRC(RegTimerClock,0x0D); // TAutoRestart=0,TPrescale=64*128   
          WriteRawRC(RegTimerReload,0x41);// TReloadVal = 'h41 =65(dec)    
          break;   
       case 8:                         	  // (77.32 ms) FWI=8   
          WriteRawRC(RegTimerClock,0x0D); // TAutoRestart=0,TPrescale=64*128   
          WriteRawRC(RegTimerReload,0x81);// TReloadVal = 'h81 =129(dec)    
          break;   
       case 9:                         	  // (154.6 ms) FWI=9   
          WriteRawRC(RegTimerClock,0x0F); // TAutoRestart=0,TPrescale=256*128   
          WriteRawRC(RegTimerReload,0x41);// TReloadVal = 'h41 =65(dec)    
          break;   
       case 10:                        	  // (309.3 ms) FWI=10   
          WriteRawRC(RegTimerClock,0x0F); // TAutoRestart=0,TPrescale=256*128   
          WriteRawRC(RegTimerReload,0x81);// TReloadVal = 'h81 =129(dec)    
          break;   
       case 11:                        	  // (618.6 ms) FWI=11   
          WriteRawRC(RegTimerClock,0x13); // TAutoRestart=0,TPrescale=4096*128   
          WriteRawRC(RegTimerReload,0x11);// TReloadVal = 'h21 =17(dec)    
          break;   
       case 12:                        	  // (1.2371 s) FWI=12   
          WriteRawRC(RegTimerClock,0x13); // TAutoRestart=0,TPrescale=4096*128   
          WriteRawRC(RegTimerReload,0x21);// TReloadVal = 'h41 =33(dec)    
          break;   
       case 13:                        	  // (2.4742 s) FWI=13   
          WriteRawRC(RegTimerClock,0x13); // TAutoRestart=0,TPrescale=4096*128   
          WriteRawRC(RegTimerReload,0x41);// TReloadVal = 'h81 =65(dec)    
          break;   
       case 14:                        	  // (4.9485 s) FWI=14   
          WriteRawRC(RegTimerClock,0x13); // TAutoRestart=0,TPrescale=4096*128   
          WriteRawRC(RegTimerReload,0x81);// TReloadVal = 'h81 =129(dec)    
          break;   
       case 15:                        	 	// (4.9485 s) FWI=14   
          WriteRawRC(RegTimerClock,0x9); 	// TAutoRestart=0,TPrescale=4096*128   
          WriteRawRC(RegTimerReload,0x0ff); // TReloadVal = 'h81 =129(dec)    
          break;   
       */
	   
	   default:                           
          WriteRawRC(RegTimerClock,0x19); 	 	// TAutoRestart=0,TPrescale=128   
          WriteRawRC(RegTimerReload,tmoLength); // TReloadVal = 'h6a =tmoLength(dec)    
          break;   
    }        
    WriteRawRC(RegTimerControl,0x06); 
 } 
 
 

//************************************************************************
// mif_config
// input:tmolength
//************************************************************************
char  mif_config(void)
{
   ClearBitMask(RegControl,0x08);				// crypto1 OFF

   // kalibrace oscilatoru
   WriteRawRC(RegClockQControl,0x0);
   WriteRawRC(RegClockQControl,0x40);
   wait_ms(1); 						 			// wait - calibration in progress
   ClearBitMask(RegClockQControl,0x40); 		// clear bit ClkQCalib for 

   WriteRawRC(RegTxControl,0x5b);
   
   WriteRawRC(RegCwConductance,0x0F);
   //WriteRawRC(RegCwConductance,0x3F);			// vykon do anteny 
   //WriteRawRC(RegModConductance,0x3F);       		
   WriteRawRC(RegModConductance,0x3F);       	// vykon do anteny 
      
   WriteRawRC(RegCoderControl,0x19);
   WriteRawRC(RegModWidth,0x13);    			// sirka modulacniho pulsu         
 
   WriteRawRC(RegDecoderControl,0x08);
//toto   WriteRawRC(RegDecoderControl,0x28);
   WriteRawRC(RegBitPhase,0xAD);	
   
   
   // NASTAVENI RX sekce - GAIN
    #define GAIN_20dB			0x00
	#define GAIN_24dB			0x01
	#define GAIN_31dB			0x02
	#define GAIN_35dB			0x03
	#define LFP_OFF				0x04
	#define ISO_SELECTION_1443	0x10
	#define ISO_PULSES			0x60
	//WriteRawRC(RegRxControl1, ISO_PULSES | ISO_SELECTION_1443 /*| LFP_OFF*/ | GAIN_24dB); 
	
	 WriteRawRC(RegRxControl1, ISO_PULSES | ISO_SELECTION_1443 /*| LFP_OFF*/ | GAIN_35dB); 
//puvosni nastaveni ctecek
// NASTAVENI RX sekce - GAIN
//		WriteRawIO(RegRxControl1,0x73);			// Gain 35dB
// NASTAVENI RX sekce -TRESHOLD        
//		WriteRawIO(RegRxThreshold,0xee);
		
		
		
		
   // NASTAVENI RX sekce -TRESHOLD        
//   WriteRawRC(RegRxThreshold,0xff);		// limita RX signalu, pod tuto uroven to dekoder neprijima
   WriteRawRC(RegRxThreshold,0xee);		// limita RX signalu, pod tuto uroven to dekoder neprijima
  
   WriteRawRC(RegBPSKDemControl,0);
   //totoWriteRawRC(RegRxControl2,0x01);		// bez auto power down, interni demodulator

	   		
   WriteRawRC(RegRxWait,0x04);
   WriteRawRC(RegChannelRedundancy,0x0F);  		// CRC ON  
   WriteRawRC(RegCRCPresetLSB,0x63);
   WriteRawRC(RegCRCPresetMSB,0x63);

//   WriteRawRC(RegMfOutSelect,0x00);		// MFOUT - NIC
   //WriteRawRC(RegMfOutSelect,0x03);			// MFOUT - TX serial data stream 
     //WriteRawRC(RegMfOutSelect,0x05);			// MFOUT - manchester demodulator serial
   WriteRawRC(RegMfOutSelect,0x04);			// MFOUT - demodulator pulsy
  
   //WriteRawRC(RegTestDigiSelect, 0xf4);		// override MFOUT - test signal - scard
  // WriteRawRC(RegTestDigiSelect, 0x96);		// override MFOUT - test signal - 13.56Mhz output
   //WriteRawRC(RegTestDigiSelect, 0xc4);		// override MFOUT - test signal - internal clock
   //WriteRawRC(RegTestDigiSelect, 0xd4);		// override MFOUT - test signal - scoll
   //WriteRawRC(RegTestDigiSelect, 0xe4);		// override MFOUT - test signal - svalid
                    
   WriteRawRC(RFU27,0x00);   	      

   WriteRawRC(RegFIFOLevel,0x3F);
   //WriteRawRC(RegFIFOLevel,0x04);

//   WriteRawRC(RegTimerClock,0x07);
  // WriteRawRC(RegTimerReload,0x0A);
   //WriteRawRC(RegTimerControl,0x06);   

   WriteRawRC(RegIRqPinConfig,0x02 | 0x01);      	// finkce IRQ pinu CMMOS push-pull
   //WriteRawRC(RegInterruptEn, 0x80 | 0x18); 			// povol RX/TX interrupts
   
   //WriteRawRC(RegInterruptEn, 0x80 | 0x10); 			// povol TX interrupts - NA PRIKAZ TRANSCIEVE
   //WriteRawRC(RegInterruptEn, 0x80 | 0x08); 			// povol RX interrupts
   //WriteRawRC(RegInterruptEn, 0x80 | 0x04); 			// povol IDLE interrupts
    // WriteRawRC(RegInterruptEn, 0x80 | 0x3f); 			// povol RX interrupts
	  
   //WriteRawRC(RegInterruptRq,0x7F); 				// reset interrupt requests
   //WriteRawRC(RegInterruptRq,0x3F); 				// reset interrupt requests
   	
   WriteRawRC(RFU2E,0x00);
   WriteRawRC(RFU2F,0x00);	  

   PcdSetTmo(106);
   wait_ms(1);   

   //int0ic.byte = INT_LEVEL_INT0;	// INT0 priority
//   PcdAntennaOn();   
}



//************************************************************************
// PcdComTransceive
// 
//************************************************************************
tUInt PcdComTransceive( struct TranSciveBuffer *pi)
{
   unsigned char recebyte;
   tUInt status;
   unsigned char irqEn;
   unsigned char waitFor;
   unsigned char lastBits;
   unsigned char n;
   unsigned int i;
   tUChar mask, temp;

   recebyte = 0;
   irqEn   = 0x00;
   waitFor = 0x00;

   switch (pi->MfCommand)
   {
      case PCD_IDLE:
         irqEn   = 0x00;
         waitFor = 0x00;
         break;
		 
      case PCD_WRITEE2:
         irqEn   = 0x11;
         waitFor = 0x10;
         break;
		 
      case PCD_READE2:
         irqEn   = 0x07;
         waitFor = 0x04;
         recebyte=1;
         break;
		 
      case PCD_LOADCONFIG:
      case PCD_LOADKEYE2:
      case PCD_AUTHENT1:
         irqEn   = 0x05;
         waitFor = 0x04;
         break;
		 
      case PCD_CALCCRC:
         irqEn   = 0x11;
         waitFor = 0x10;
         break;
		 
      case PCD_AUTHENT2:
         irqEn   = 0x04;
         waitFor = 0x04;
         break;
		 
      case PCD_RECEIVE:
         irqEn   = 0x06;
         waitFor = 0x04;
         recebyte=1;
         break;
		 
      case PCD_LOADKEY:
         irqEn   = 0x05;
         waitFor = 0x04;
         break;
		 
      case PCD_TRANSMIT:
         irqEn   = 0x05;
         waitFor = 0x04;
         break;
		 
      case PCD_TRANSCEIVE:
         irqEn   = 0x3D;
         waitFor = 0x04;
         recebyte=1;
         break;
		 
      default:
         pi->MfCommand = MIFARE_UNKNOWN_COMMAND;
         break;
   }
   
   if (pi->MfCommand != MIFARE_UNKNOWN_COMMAND)
   {
	  WriteRawRC(RegPage,0x00);
      WriteRawRC(RegInterruptEn,0x7F);		// zakaze vsechna preruseni
      WriteRawRC(RegInterruptRq,0x7F);		// smaze interrupt flagy
    
	  WriteRawRC(RegCommand,PCD_IDLE);
      // !!! POZOR ZDE NIKDY NEMAZAT FIFO JINAK TO JDE CELE DO SRACEK !!!!
	  //FlushFIFO();				
      WriteRawRC(RegInterruptEn,irqEn|0x80);

	  
	  for (i=0; i<pi->MfLength; i++)
       {
         WriteRawRC(RegFIFOData, pi->MfData[i]);
		 ClearWDT();
       }
	  WriteRawRC(RegCommand, pi->MfCommand);
	  	  	  	  	  	 
	 //------------------------------------
	 // toto je timeout na odpoved z karty
	  i = 0x20;			
	  //i = 0x40;			
      do
      {
         n = ReadRawRC(RegInterruptRq);			// osahavani interrupt registru
         i--;
		 ClearWDT();
		 wait_us_range(DELAY_100us);
      }
      while ((i!=0) && !(n & irqEn & 0x20) && !(n & waitFor));
	//------------------------------------

   
	  status = MIFARE_TRANS_ERR;
      
	  if ((i!=0) && !(n & irqEn & 0x20))
       {
	     // v pripade pristupu do EEPROM nenacitat RegErrorFlag register, jsou v nem mozne chybyh ktere nepotrebujeme znat
		 if ( (pi->MfCommand == PCD_WRITEE2) || (pi->MfCommand == PCD_READE2) )
		  mask = 0x20;			// monitorovat pouze bit AccessError
		 else
		  mask = 0x17;
		  
		 if (!(ReadRawRC(RegErrorFlag)&mask))
         {
            status = NO_ERROR;
		    if (recebyte)
             {
			    n = ReadRawRC(RegFIFOLength);
                lastBits = ReadRawRC(RegSecondaryStatus) & 0x07;
                if (lastBits)
                 {
                   pi->MfLength = (n-1)*8 + lastBits;
                 }
                else
                 {
                   pi->MfLength = n*8;
                 }
                
				if (n == 0)
                 {
                   n = 1;
                 }
                
				for (i=0; i<n; i++)
                 {
                    pi->MfData[i] = ReadRawRC(RegFIFOData);
                 }
             }	// konec if (recebyte)
          }		// konec //if (!(ReadRawRC(RegErrorFlag)&mask))
      }			// konec if ((i!=0) && !(n & irqEn & 0x20))
	  
	// vyprsel nastaveny vnitrni timeout MFRC531    
	else if (n & irqEn & 0x20)						
     {
	   status = MIFARE_NOTAG_ERROR;   
     }
 
 	else if (!(ReadRawRC(RegErrorFlag)&0x17))
	 {
       if ( (pi->MfCommand != PCD_WRITEE2) && (pi->MfCommand != PCD_READE2) )		// v pripade operace s EEPROM 
	    status = MIFARE_READER_TIMEOUT_ERR; 										// nehlasit chybu
	   else 
	    status = NO_ERROR;	
	 }
    else
     {
	   status = MIFARE_TRANS_ERR;
	 }

      
      WriteRawRC(RegInterruptEn,0x7F);
      WriteRawRC(RegInterruptRq,0x7F);			// smaze interrupt flagy
     
   }
   
   	 
			  
   return status;
}

