#include "includes.h"

extern tsEDK 			EDK;
extern tsAppCB  		appCB;
extern tsRD3_packet	 	RD3_packet;
extern DATA_PARSING		gData;



/************************************************************************************/
// MifareReadWriteBlock()
// rutina pro zapis i cteni z bloku karty
// pro vymenu dat slouzi *rwBuffer
/************************************************************************************/
#if defined INTERFACE_RD3 && defined  READER_MIFARE
tUInt MifareReadWriteBlock( tUChar block, tUChar  *plain_key, tUChar keyAB, tUChar *cardID, tUChar *rwBuffer)
{
  tUInt status;
  tUChar coded_key[12];
  tUInt sector;				// cislo sektoru pro autenzitaci
  tUInt trailer;			// trailer block s opravnenim 
  tUChar authKey;			// zpusob autentizace - klicem A nebo klicem B 
// -------------------------------------------------------------------------  
// nejdrive provest prikaz SELECT - karta se vybere pro dalsi komunikaci
  status = PcdSelect( PICC_ANTICOLL1, (tUChar*)&cardID[0], (tUChar*)&gCard.card_type[2]);		// zde se ulozi SAK
  if (status != NO_ERROR)
   {
	 PcdHalt();									// ukoncit praci s kartou a ven
	 return (MIFARE_SELECT_ERROR);	
   }

   // ihned po nacteni karty probliknout zelenou LED, jako indikaci cteni
   // jelikoz zde nejde pouzit funkci GUI, reseno takto
   RestoreIdleLedState();

  
		
// -------------------------------------------------------------------------	  
// pro autentizaci se pouzije bud predany klic z paketu nebo klic ulozeny v EEPROM MFRC531
  if (RD3_packet.kid != 0x00)							// pokud v .kid neni 0x00 znamena to nahrat klic z EEPROM
   {													// v EEPROm je jiz klic ulozen v kodovanem stavu
	status = PcdLoadKeyE2(GetEEAdr(RD3_packet.kid-1));	// nahrat klic z pozadovane pozice z EEPROM, pozor upravit offset na 0-xx						
    if (status != NO_ERROR)
	 return (MIFARE_LOAD_KEY_ERROR);				// nepodarilo se nahrat klic 
   }
  else												// pokud se klic bere z paketu, je nutne jej prekodovat
   { 
     ChangeCodeKey (&plain_key[0], &coded_key[0]);	// prekodovani klicu do pozadovaneho formatu pro MFRC531
     status = PcdLoadKey( &coded_key[0]);			// nahrati klice do RAM cteciho obvodu
   }

  if (status != NO_ERROR)							// pokud vznikne chyba pri nahravani tak ukoncit s chybou
   {
     return (MIFARE_LOAD_KEY_ERROR);	
   }

// -------------------------------------------------------------------------
// nasleduje pokus o autentizaci daneho bloku se zadanym klicem a cislem karty
  sector = block/4;								// cislo sektoru pro autentizaci
  trailer = (sector*4)+3;   		    		// adresa bloku s opravnenim	

  wait_ms(1);	   
  
  if (RD3_packet.ktype == 'A')  	 authKey = PICC_AUTHENT1A;	// pro autentizaci se pouzije typ klicee KEY_A
  else if (RD3_packet.ktype == 'B')  authKey = PICC_AUTHENT1B;	// pro autentizaci se pouzije typ klicee KEY_B
  
  status = PcdAuthState(authKey, trailer, &cardID[0]);	// autentizovat pristup do sektoru 	 
  if (status != NO_ERROR)
   {
     PcdHalt();											// ukoncit praci s kartou a ven
     return (MIFARE_AUTH_ERR);
   }


// -------------------------------------------------------------------------	   
// ZAPIS NA KARTU
// -------------------------------------------------------------------------
  if ( appCB.mode & CARD_WRITE_MODE )
   {
	 switch (gCard.mif_rwmode)
	  {
	 	 // zapis do DATA blocku
		 case WRITE_DATA_BLOCK:	
      	 case FORMAT_TRAILER_BLOCK:	
			status = PcdWrite( block,  (tUChar*)&rwBuffer[0]);
	  	 break;

	     // zapis do VALUE blocku
		 case WRITE_VALUE_BLOCK:
			TranscodeValueBlock( &RD3_packet.data[0], RD3_packet.block);
		    status = PcdValue(PICC_WRITE, RD3_packet.block, &RD3_packet.data[0], 16);		// v data[] je hodnota k zapisu
	  	 break;
  	 
		 // increment VALUE blocku
	 	 case INCREMENT_VALUE_BLOCK:	
	  	    ValueBlockChangeOrder( &RD3_packet.data[0]);									// prohodit MSB->LSB
			status = PcdValue(PICC_INCREMENT, RD3_packet.block, &RD3_packet.data[0], 4);	// v data[] je hodnota incrementu
	  	 break;
		 
  	 	 // decrement VALUE blocku
	 	 case DECREMENT_VALUE_BLOCK:	
		    ValueBlockChangeOrder( &RD3_packet.data[0]);									// prohodit MSB->LSB
			status = PcdValue(PICC_DECREMENT, RD3_packet.block, &RD3_packet.data[0], 4);	// v data[] je hodnota incrementu
		 break;
		 
		default: break;
	  }		// konec switche
	 
	 
	 // provedeni operace ukoncit praci s kartou 
	 PcdHalt();									// ukoncit praci s kartou a ven

     // chyba zapisu nebo operace s VALUE blokem
	 if (status != NO_ERROR)									
	  {
	 	switch (gCard.mif_rwmode)
	     {
 		  case WRITE_DATA_BLOCK: 	  gCard.mif_status = MIFARE_WRITE_ERR; 	
      	  case FORMAT_TRAILER_BLOCK:  gCard.mif_status = MIFARE_WRITE_ERR;
		   break;	
		  case WRITE_VALUE_BLOCK: 	  gCard.mif_status = MIFARE_WRITE_ERR;
		   break;	
		  case INCREMENT_VALUE_BLOCK: gCard.mif_status = MIFARE_INCR_ERR;
		   break;
		  case DECREMENT_VALUE_BLOCK: gCard.mif_status = MIFARE_DECR_ERR;
		   break;	 
		  default:
		   break;
		 }

 		#if defined INTERFACE_EDK || defined INTERFACE_RD3 || defined  READER_MIFARE
		  RD3_SendPacket_WriteAck();        		  
		#endif
		
		return (MIFARE_WRITE_ERR);				// operace zapis neprosla
	  }
  
   }			// konec rezimu zapis do bloku
// -------------------------------------------------------------------------	   
// CTENI Z KARTY
// -------------------------------------------------------------------------
  else	// rezim cteni z karty
   {
    status = PcdRead( block, (tUChar*)&rwBuffer[0]);		// nacist data do pozadovaneho bufferu - 16bajtu
    if (status != NO_ERROR)
     {
       PcdHalt();
       return (MIFARE_READ_ERR);
     }
   }
// -------------------------------------------------------------------------
 
  PcdHalt();					// ukoncit praci s kartou 
  
  return(NO_ERROR);				// nacteni bloku probehlo OK

}

#endif