#include "includes.h"


extern tUChar temp_cardId[10];
extern tsRD3_packet	 	RD3_packet;
extern tUChar authOk;

// informacni promena posledni pouzity klic
// index 0xFF znamena inicializovany stav, jinak index klice v EEPROM
tUChar lastKeyAPos;
tUChar lastKeyBPos;

// moznosti default klicu NXP a INFINEON - (klice pro transport configuration)
#if defined INTERFACE_RD3 && defined  READER_MIFARE
const char defaultKeys[] = {
        					 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,		// default klic MIFARE-NXP A or B
        					 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,		// default klic MIFARE-INFINEON A
        					 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,		// default klic MIFARE-INFINEON B
							 0xa0,0xb0,0xc0,0xd0,0xe0,0xf0, 	
							 0xa1,0xb1,0xc1,0xd1,0xe1,0xf1, 	
        					 0x4d,0x3a,0x99,0xc3,0x51,0xdd,		
        					 0x1a,0x98,0x2c,0x7e,0x45,0x9a,
        					 0xd3,0xf7,0xd3,0xf7,0xd3,0xf7,
							 0xaa,0xbb,0xcc,0xdd,0xee,0xff,
							 0x00,0x00,0x00,0x00,0x00,0x00,							 
	   					   };
#endif
    


/******************************************************************************
* PCD_StopCrypto1
******************************************************************************/
void PCD_StopCrypto1(void)
{
  ClearBitMask(RegSecondaryStatus,0x08);		  // Clear MFCrypto1On bit
} 

							 
/******************************************************************************************
* PCD_Stop_and_FiledOff
* vypne pole
******************************************************************************************/
void PCD_Stop_and_FiledOff(void)
{
  PCD_StopCrypto1();
  PcdAntennaOff();
  wait_ms(100);					// poctak dele nez 5ms
}
	  
	  
/******************************************************************************************
* GetEEAdr
* prekodovani bloku EEPROM na fyzickou adresu
******************************************************************************************/
tUInt GetEEAdr(tUChar offset)
{
  return (( offset*16) + PCD_EEPROM_KEYS_START_ADDRESS);
}


/******************************************************************************************
* RestartField
* restartuje cteci pole a hlavne zrusi CRYPTO rezim
******************************************************************************************/
void RestartField(void)
{
  PcdHalt();
  PCD_StopCrypto1();
	  
  PcdAntennaOff();
  wait_ms(10);					// pockat dele nez 5ms
  PcdAntennaOn();
  wait_ms(10);					// pockat dele nez 5ms
}	  



/******************************************************************************************
* FindAndSelectCard
* provede vyber karty s pozadovanym ID
******************************************************************************************/
tUInt FindAndSelectCard(void)
{
 tUInt status;
 tUChar Id[4];
 

	
 status = PcdRequest( PICC_REQSTD, (tUChar*)&Id);							// provest prikaz REQA

 if (status == READER_TAG_OK)								
  {
    status = PcdAnticoll(PICC_ANTICOLL1, (tUChar*)&Id[0]);									// provest prikaz ANTICOLL
    if (status == NO_ERROR)
	 {
	   // tady staci provest prikaz SELECT pouze na zaklade CASCADE LEVEL1
	   status = PcdSelect(PICC_ANTICOLL1, (tUChar*)&Id, (tUChar*)&gCard.card_type[2]);		// provest prikaz SELECT	
	 }
  }
 else
  status = MIFARE_NOTAG_ERROR;

  return status;
}




	   
/******************************************************************************************
* AuthorizeCardAcces
* pokusi se znovu autorizovat kartu pro pristup se zadanym klicem
******************************************************************************************/
#if defined INTERFACE_RD3 && defined  READER_MIFARE 
tUInt AuthorizeCardAccess(tUChar block, tUChar auth_mode, tUChar *uid)
{
  tUInt status;
  tUChar Id[4];
  tUInt num_keys;
  tUChar i;
  
  status = NO_ERROR;
  
  if (auth_mode == PICC_AUTHENT1A) 
   lastKeyAPos = 0xFF;					// informacni promena posledni pouzity klic, index 0xFF znamena inicializovany stav
  
  if (auth_mode == PICC_AUTHENT1B)
   lastKeyBPos = 0xFF;					// informacni promena posledni pouzity klic, index 0xFF znamena inicializovany stav


	 
 // projde se cely prostor klicu v EEPROM - pametove pozice 1-10 (offset 0-9) jsou klice kopirovane z ROM, nelze je smazat
 // tato funkce se vola 2x, pokazde s jinym parametrem - KEY_A nebo KEY_B
 num_keys = MAX_KEYS;										// projit cely prostor s klici
 for (i = 0; i < num_keys; i++)								// smycka pocet default klicu 
  {
	status = PcdLoadKeyE2(GetEEAdr(i));						// nahrat default klic z pozice EEPROM do RAM cteciho obvodu
    if (status != NO_ERROR)
	return (MIFARE_LOAD_KEY_ERROR);							// nepodarilo se nahrat klic 
	
 	LED_GRN_FLIP;			   								// blikat zelenou LED pri pokusech o autorizaci, at je videt ze se neco deje
 
	// zkusit autorizaci typem klice A/B - podle predaneho parametru
	status = PcdAuthState(auth_mode, block, &uid[0]);	
	if (status == NO_ERROR)									// podarilo se autentizovat?
	 {
	   if (auth_mode == PICC_AUTHENT1B) 
	    {
		  lastKeyBPos = i;		// index B klice
	    }
	   else if (auth_mode == PICC_AUTHENT1A)
	    {
		  lastKeyAPos = i;		// index A klice
		}
	   
	   authOk = 1;	  										// flag autorizace probehla OK - pro zobrazeni vypisu
       return (status);
	 }	
 
    // pro kazdy sector trailer je pred prikazem select potreba restartovat pole
   if ((block % 4)==3)
    {
	  RestartField();
	}
	 
  status = FindAndSelectCard();		// provest SELECT karty
  if (status !=  NO_ERROR)
    return (status);	

}


  return (MIFARE_AUTH_ERR);			// nepodarilo se autentizovat zadnym z klicu - smula 

}
#endif
   
	
/******************************************************************************************
* MifareInitReader
*
*******************************************************************************************/
unsigned int MifareInitReader(void)   
{   
  unsigned int _status;   

  _status = RC500InterfaceInit();   
  if (_status != NO_ERROR ) return (_status);
	
  mif_config();						// MFRC531 configuration  

#if defined INTERFACE_RD3 && defined  READER_MIFARE
  _status = LoadDefaultKeys();	// nahraje default klice do EEPROM
  if (_status != NO_ERROR ) return (_status);
#endif
  				   
  return (NO_ERROR);
 }   


/******************************************************************************************
* MifareReadId
*
******************************************************************************************/
unsigned int MifareReadId( tUChar *card)
{
  unsigned char status; 
 
   PcdAntennaOn();
   wait_ms(10);					// poctak dele nez 5ms
   
   status = MifareFindCard( &card[0] );
		
   PcdAntennaOff();
   wait_ms(10);

   return (status);
}



/******************************************************************************************
* CardIsRemovedFromField
*
* fce ceka na oddaleni karty z pole
******************************************************************************************/
unsigned int CheckCardIsRemovedFromField( void )
{
  tUInt status; 
  tUChar tempId[4];

  // flag CARD_RW_BLOCK znamena rezim nacitani bloku karty MIFARE
  // cekame na oddaleni karty ze ctecky pak ukoncime tento rezim  														
  
   if (gCard.mif_flag & CARD_RW_DONE)
   {
	 PcdAntennaOff();										// pokud by byla antena zapla, tak vypnout
     wait_ms(50);											// pockat dele nez 5ms
	
  	 PcdAntennaOn();										// znovu zapnout antenu
     wait_ms(50);											// pockat dele nez 5ms
	 status = PcdRequest( PICC_REQSTD, (tUChar*)&tempId);	// osahavani pole
	 PcdAntennaOff();										// vypnout antenu
     wait_ms(50);					    					// pockat dele nez 5ms
   
	 if ( status == MIFARE_NOTAG_ERROR)						// cekat na oddaleni karty z pole 
      {
        appCB.mode &= ~CARD_RW_BLOCK; 						// ukoncit tento rezim a uz sem nevstupovat
		gCard.mif_flag &= ~CARD_RW_DONE;					// smazat flag
		EDK.sys_flag &= ~FLAG_RD3_PACKET_SENDED;			// smazat flag
		appCB.mode &= ~MIFARE_DUMP_MODE;					// ukoncit rezim DUMP
		EDK.counter.led_cycles = 1;							// donuti zelenou LED prestat blikat
	    return (TRUE);
	  }
   }

   // kvuli dotazu $FST - obnovovat stavy promenych - jako ze je karta porad v poli nactena
   gCard.old_state = READER_TAG_OK;
   gCard.state = READER_TAG_OK;
   
   return (FALSE);
}

   


/******************************************************************************************
* MifareReadIdAndRWBlock
*
******************************************************************************************/
#if defined INTERFACE_RD3 && defined  READER_MIFARE
unsigned int MifareReadIdAndRWBlock(void )
{
  tUInt status; 
  tUChar tempId[10];
  tUChar useKey;


  // osahavat pole jestli byla karta oddalena aby se mohl ukoncit tento rezim
  CheckCardIsRemovedFromField();
  
  // pokud jeste nebyla nactena karta tak nacitat
  if (!(gCard.mif_flag & CARD_RW_DONE))		
   {
     my_memset((tUChar*)&tempId, 0, sizeof(tempId) );
	 status = MifareFindCard( (tUChar*)&tempId );
	
	 // karta nalezena v poli
     if (status == READER_TAG_OK)
      {
       gCard.old_state = 0;		// v rezimu prace s bloky nutno zabranit normalnimu zpracovani karty	- odeslani paketu
       gCard.state = 0;
	   status = 0;				// inicializace status kvuli kontrole UID nize
   
	   // v rezimu DUMP nezname karty UID samozrejme neoverovat
	   if (!(appCB.mode & MIFARE_DUMP_MODE))		
        {
	     // pred zahajenim jakekoliv prace s kartou je nutne zkontrolovat jestli opravdu pristupujeme ke spravne karte
	     status = my_memcmp( (tUChar*)&tempId, (tUChar*)&RD3_packet.id, 4);  	
	    }
       
	   // kontrola na UID v poradku
	   if (status == 0 )  								
        {
	     // ~~~~~ rezim zapisu na kartu ~~~~~
	     if ( appCB.mode & CARD_WRITE_MODE )		
	      {
			useKey = KEY_B;
			//if (gCard.mif_rwmode == WRITE_DATA_BLOCK)	useKey = KEY_A; 
			status = MifareReadWriteBlock(RD3_packet.block, (tUChar*)&RD3_packet.key, useKey, (tUChar*)&tempId, (tUChar*)&RD3_packet.data);	
		  }
		 
		 // ~~~~ rezim cteni z karty ~~~~
		 if ( !(appCB.mode & CARD_WRITE_MODE) )
	      {
			// aktivni rezim DUMP karty
		    if (appCB.mode & MIFARE_DUMP_MODE)	
		     {
		        // nejdrive provest prikaz SELECT
			        status = PcdSelect( PICC_ANTICOLL1, (tUChar*)&tempId[0], (tUChar*)&gCard.card_type[2]);	// ulozit SAK
			        if (status == NO_ERROR)								// pokud SELECT neprobehl OK
   			         {
				      #ifdef INTERFACE_RD3
					   PICC_DumpToSerial( (tUChar*)&tempId[0]);		// PROVEST VYPIS DO SCI
					  #endif 
			          gCard.mif_flag |= CARD_RW_DONE;				// simulovat ukonceni operace s kartou
   			         }
			 }				// konec if (appCB.mode & MIFARE_DUMP_MODE)


			 // normalni rezim cteni
			 else
			  {
			   status = MifareReadWriteBlock(RD3_packet.block, (tUChar*)&RD3_packet.key, KEY_A, (tUChar*)&tempId, (tUChar*)&gCard.sector_data );	
		       if (status != NO_ERROR)						// pokud cteni v jednom z rezimu je neuspesne, hlasit chybu
		        {
	 		      PcdHalt();								// ukoncit praci s kartou
			    }
			  }		// konec else normalni rezim cteni
		   }		// konec 	 if ( !(appCB.mode & CARD_WRITE_MODE) )
		   

		// operace cteni dokoncena, at s chybou nebo bez
		  gCard.mif_flag |= CARD_RW_DONE;				// flag operace cteni probehla 
	      gCard.mif_status = status;					// navratovy kod operace READ
          if (status != NO_ERROR)
		   {
		     #ifdef INTERFACE_RD3
		      RD3_ErrorBeep();
			 #endif 
		   }	// indikace bip-bip
		  
		}												// konec if (status == 0 ) - sedi UID 
	  else												// pristup na nespravnou kartu - nesedi jeji UID s pozadavkem v paketu
	   {
		 gCard.mif_flag |= CARD_RW_DONE;				// flag operace cteni probehla 
	     gCard.mif_status = MIFARE_SERNR_ERR;			// navratovy kod operace 
		 
		 #ifdef INTERFACE_RD3
		  RD3_ErrorBeep();								// indikace bip-bip
		 #endif 
		 //RestoreIdleLedState();
		 //SetLed(0xff, GUI_RED_STATIC_MODE|GUI_GRN_STATIC_MODE); // value LED - sviti trvale
	   }
	   
	  }			// konec  if (status == READER_TAG_OK)
   }			// konec  if (!(gCard.mif_flag & CARD_RW_DONE))		



//-----------------------------------------------   	   
   // cteni bloku neprobehlo
   if (!(gCard.mif_flag & CARD_RW_DONE))			   
    {
	  PcdAntennaOff();							// antenu vypnout
      wait_ms(10);								// nahodi se sama ve cteci smycce
	}
//-----------------------------------------------
   
   return (status);
}
#endif

 
/******************************************************************************************
* MifareFindCard
*
******************************************************************************************/
unsigned int MifareFindCard(tUChar *serial_num)
{
   unsigned char _status;
   unsigned int  _atqa;			// toto je ATQA (Answer to Request Type A)

   tUChar dKeys[12];
   tUChar status;

   PcdAntennaOff();				// pokud by byla antena zapla, tak vypnout
   wait_ms(10);					// poctak dele nez 5ms
  
   PcdAntennaOn();				// znovu zapnout antenu
   wait_ms(10);					// poctak dele nez 5ms
	 
	// posle dotaz REQSTD - dotaz na jednu kartu
	_status = PcdRequest( PICC_REQSTD, &serial_num[0]);				
	if(_status == READER_TAG_OK)							// karta detekovana v poli
 	 {
       wait_ms(1);
	   status = PcdAnticoll(PICC_ANTICOLL1, &serial_num[0]);
	   if (status != NO_ERROR)
	    {
		  PcdHalt();										// ukoncit praci s kartou a ven
		  return (-1);	
		}
	   
	   // TADY je podpora CASCADE TAG, zatim do urovne CL2
	   if ( serial_num[0] == 0x88)							// jedna se kaskadovy tag, nasleduji dalsi bajty
        {
		  status = PcdSelect( PICC_ANTICOLL1, (tUChar*)&serial_num[0], (tUChar*)&gCard.card_type[2]);		// provest prikaz SELECT	
	      if (status != NO_ERROR)							// chyba prikazu SELECT
	       {
		    PcdHalt();										// ukoncit praci s kartou a ven
		    return (-1);	
		   }

		  // PO PROVEDENI PRIKAZU SELECT, karta vraci SAK
		  // 0x24 pro MIFARE DESFIRE
		  status = PcdAnticoll(PICC_ANTICOLL2, &serial_num[4]);
	      if (status != NO_ERROR)							// chyba prikazu ANTICOLL2
	       {
		    PcdHalt();										// ukoncit praci s kartou a ven
		    return (-1);	
		   }
	      
		  my_memcpy ( (tUChar*)&serial_num[0], (tUChar*)&serial_num[1], 7);
		  serial_num[7] = 0;								// odmazat posledni bajt
		}													// konec if ( serial_num[0] == 0x88)
	   
	   return(READER_TAG_OK); 								// vraci UID		  
  	 }	


	else if (_status != NO_ERROR)							// karta detekovana ale nastala nejaka chyba
 	  return (READER_NO_TAG);								// pricina vetsiny chyb je preruseni komunikace s kartou pri 

}


/******************************************************************************************
* MifareInitReader
* nahraje default klice do EEPROM 
* pro default klice je rezervovany bloky EEPROM 8-15 (0x80-0xFF)
* nasleduje prostor uzivatelskych klicu - bloky 16-31 (0x100-0x1FF)
*******************************************************************************************/
#if defined INTERFACE_RD3 && defined  READER_MIFARE
tUInt LoadDefaultKeys(void)				
{
  tUChar coded_key[12];					
  tUInt status;
  tUInt num_keys;
  tUInt i,j;
  
  i = 0;
  j = 0;
  
  
  // pocet definovanych default klicu 
  num_keys = sizeof(defaultKeys) / 6;	
  
  // prostor default klicu omezit na 8
   if (num_keys > MAX_DEFAULT_KEYS)										// kontrolovat max. pocet default klicu
    return (MIFARE_LOAD_KEY_ERROR);

  // smycka projde seznam default klicu a nahraje je do EEPROM MFRC531 do bloku umisteni klicu
  for (i = 0; i < MAX_DEFAULT_KEYS; i++)								// projde vsechny pozice
  {
    if (j++ < num_keys)													// klice jsou definovany
     {
	   ChangeCodeKey ( (tUChar*)&defaultKeys[i*6], &coded_key[0]);	// prekodovani klicu do pozadovaneho formatu pro MFRC531
	 }  
	else																// pokud je definovano mene nez pozadovany pocet klicu (8)	
	 {																	// tak vyplnit prostor v EEPROm default klicem 
		ChangeCodeKey ( (tUChar*)&defaultKeys[0], &coded_key[0]);		// vzit prvni default klic FFFFFFFFFFFF
	 }

     status = PcdWriteE2( GetEEAdr(i), 16, (tUChar*)&coded_key[0]);		// nahrati klice do cteciho cipu napozadovanou adresu
     if (status != NO_ERROR)
	   return (MIFARE_EEPROM_WRITE_ERR);								// nepodarilo se ulozit klic do EEPROM
  }
  
}
#endif


/******************************************************************************************
* SaveKeyToEeprom
* prekoduje klic do pozadovaneho formatu a ulozi do EEPROM na pozadovanou pozici
* pokud je parametr 0xFF tak celou oblast klicu inicializuje poskytnutym klicem
*******************************************************************************************/
#if defined INTERFACE_RD3 && defined  READER_MIFARE
tUInt SaveKeyToEeprom(void)
{
  tUInt status;			 
  tUChar coded_key[12];
  tUChar loop;
  tUChar i;
  tUChar block;
  tUChar offset;

  
  if (RD3_packet.block == 0xFF)											// pozadavek inicializovat prostor user klicu, pozice 8-23
   {
     for (i = MAX_DEFAULT_KEYS; i < MAX_KEYS; i++)						// projde vsechny uzivatelske pozice
	  {
		ChangeCodeKey ( (tUChar*)&defaultKeys[0], &coded_key[0]);		// prekodovat klic FFFFFFFFFFFF
        status = PcdWriteE2( GetEEAdr(i), 16, (tUChar*)&coded_key[0]);	// nahrati klice do cteciho cipu napozadovanou adresu
        if (status != NO_ERROR)
	     return (MIFARE_EEPROM_WRITE_ERR);								// nepodarilo se ulozit klic do EEPROM
	  }
     return status;														// po nahrati klicu ukoncit
   }
  
     
  // prekodovani klicu do pozadovaneho formatu pro MFRC531
  ChangeCodeKey (&RD3_packet.key[0], &coded_key[0]);		
  	 
  status = PcdWriteE2( GetEEAdr(RD3_packet.block-1), 16, (tUChar*)&coded_key[0]);	// rozsah bloku je upraveny index 8-23
   
  return status;
}
#endif

	   
	   
	   		