#include "includes.h"

tsCARD 		gCard;

extern tsEDK 	EDK;
extern tsAppCB  appCB;


// podobu pipaku blokovat cteni karty?
#define BLOCK_CARD_READING_WHILE_BUZZER_IS_ON


extern const char card[];


/*************************************************************************
*Name:		  DoEmergencyAccess
*Description: zkontroluje opravneni a otevre dvere
*************************************************************************/
#ifdef INTERFACE_RS
void DoEmergencyAccess(void)
{
#ifdef READER_MIFARE  // pro mifare nemame prostor na takove veci
 #ifndef DEMO_REZIM 
  return;
 #endif
#endif

  // pozor zmena, rozsireno pole ID[], prvni bajt je v id[1]
  if (CheckEmergencyAccess((tUChar*)&gCard.cardId[1]) == TRUE)	// kontroluji se opravneni z pameti offline karet
   {
     EDK.output |= EDK_OUT_RELAY;						// nouzove otevreni dveri
     EDK.counter.relay = EDK_PRESET_RELAY_TIME;			// na danou dobu
 	 EDK.output &= ~EDK_OUT_LED_RED;
 	 EDK.io_flag |= FLAG_GRN_FOLLOW_MODE;				// zelena bude kopirovat stav rele
	 
	 EDK.output |= EDK_OUT_BUZZER;						// soucasne s rele piska i piskac
	 EDK.counter.buzzer_time = EDK_PRESET_BUZZER_TIME;	// 
   }
  // indikovat probliknutim zelene diody neopravnenou kartu 
  // jelikoz sviti v rezimu OFFLINE obe dve, tak se rozsviti na okamzik cervena
  else
  {
 	 LED_GRN_OFF; 			// zhasnout LED natvrdo
     
	 BUZZER_ON;
	 wait_ms(150);			// pockat, o obnovit stav LED	
     BUZZER_OFF;
	 wait_ms(150);			// pockat, o obnovit stav LED	
	 BUZZER_ON;
	 wait_ms(150);			// pockat, o obnovit stav LED	
	 BUZZER_OFF;
	 
	 wait_ms(150);			// pockat, o obnovit stav LED	
	 LED_GRN_ON; 			// zhasnout LED natvrdo
  }
 

}
#endif


/*************************************************************************
*Name:		  CardInserted
*Description: detekovano prilozeni karty
*************************************************************************/
void CardInserted(void)
{

   // osetreni pro pripad ze by to proslo az sem a cislo karty bylo nulove
   if (!gCard.cardId[0] && !gCard.cardId[1] && !gCard.cardId[2] && !gCard.cardId[3])
    {
	  return;
	}
	 
	//*************************
	// vystup pres rozhrani RS
	//*************************
	#ifdef INTERFACE_RS

	if (!(EDK.input.state & EDK_IN_EHS))		// tohle u odkladacky neprovadet
	 {
  	   EDK.output |= EDK_OUT_LED_GRN;			// po prilozeni karty se rozsviti ZLUTA LED naporad
	 }											// (k cervene se prida zelena) a ceka se na odpoved od terminalu

	 
	// -------------------------------------------------------------------
	// rele a piskac spina soucasne po prilozeni karty - vhodne pro ladeni
	// EDK.output |= EDK_OUT_BUZZER;
	// EDK.counter.buzzer = EDK_PRESET_BUZZER_TIME;	
	// EDK.output |= EDK_OUT_RELAY;
	// EDK.counter.relay = EDK_PRESET_RELAY_TIME;			
	// -------------------------------------------------------------------
		GpioService();																// aktualizovat ihned stavy IO - LED+buzzer
  		if (!(EDK.input.state & EDK_IN_EHS))										// nejde o okdkladacku
		 {
			 AddReq(PRIORITY_TASK_MID | PROCESS_SCI_STATE_READER, gCard.state, 0);	// odeslani dat po RS	  
		 }
		else																		// toto plati pro odkladacku EHS
		 {
	  	 	if (!(EDK.io_flag & FLAG_EHS_CARD_PRESENCE))							// karta jeste nebyla nedetekovana
	         {
			   EDK.io_flag |= FLAG_EHS_CARD_PRESENCE;								// indikace vlozene karty (reader+optozavora)
		       EDK.sys_flag &= ~FLAG_READ_CARD; 									// zakazat cteni karty, bude povoleno jen periodicky k osahani pritomnosti karty
			   EDK.counter.ehs_check_interval = EHS_CARD_INSERTION_TIME;			// inicializovat citac osahavani vlozene karty
		       AddReq(PRIORITY_TASK_MID | PROCESS_SCI_STATE_READER, gCard.state, 0);// odeslani dat po RS	  
		  	 }	     
		  }			 

	  // REZIM MASTER KARTA - je dostupny pouze v rezimu RS, pouze pokud je nastaven flag FLAG_OFFLINE_MODE
	  if (EDK.sys_flag & FLAG_OFFLINE_MODE)			// pokud je aktivni offline rezim
	   {
	     if ( CardMemoryIsEmpty() == FALSE)			// omezeni vstupu do emergenci rezimu, pouze pokud neni cista pamet 
		  {											// generovana nejaka karta v pameti
			DoEmergencyAccess();					// provest pristup na master kartu
		  }
		 else										// pokud je aktivni OFFLINE rezim, ale nejsou ulozenz zadne master karty
		  {											// v pameti, tak je nutne obnovit default stav ledek, aby nesvitili zlute po prilozeni karty
		  	EDK.output &= ~EDK_OUT_LED_GRN;			// pohasnuti LED po prilozeni karty
			GpioService();											
		  } 							
	   }
	   		 
	#endif			// end #ifdef INTERFACE_RS


	//*********************************
	// vystup pres rozhrani EDK_WIEGAND
	//*********************************
	#ifdef INTERFACE_EDK
// v pripade typu EDK se voli vystupi format dat JUMPEREM
	if ( EDK.input.state & EDK_IN_WGOUT)							// osazen JP WIEGAND
	 {
		EDK.output &= ~EDK_OUT_LED_RED;								// pohasnuti LED po prilozeni karty
		EDK.counter.led_time = EDK_PRESET_LED_TIME;					// nastaveni doby citace x100ms

		GpioService();												// aktualizovat ihned stavy IO - LED+buzzer
		
		gCard.wg_fc = 0;											
		if ( EDK.input.state & EDK_IN_READER2)						// pokud je READER2 posila FC=1, jinak FC=0
		 {
		   gCard.wg_fc = 1;											
		 }
	    gCard.wg_cc = ((gCard.cardId[2]<<8) | gCard.cardId[3]);		// CARD CODE - posilaji se posledni 2 bajty
																	// std EDK-ACS wiegand posila posledni 2 bajty, FC=0
		AddReq(PRIORITY_TASK_MID | PROCESS_WIEGAND_OUT, gCard.wg_fc, &gCard.wg_cc);			// odeslani dat po WG	  
	 }
    else
	{
	 //******************************
	 // vystupni format ACS
	 //******************************
		EDK.sys_flag &= ~FLAG_READ_CARD;						// zakazat dalsi cteni karty do odeslani paketu 
		EDK.sys_flag |= FLAG_SEND_EDK_PACKET;					// nastavit flag - poslat data formatem ACS
		
		EDK.output &= ~EDK_OUT_LED_RED;							// pohasnuti LED po prilozeni karty
		EDK.counter.led_time = EDK_PRESET_LED_TIME;				// nastaveni doby citace x100ms
		GpioService();											// aktualizovat ihned stavy IO - LED+buzzer
		
		// generovat puls do D1
		EDK.counter.d1pulse_time = EDK_PRESET_D1_PULSE_TIME;	// jako indikaci nacteni karty pro terminal
        DATA1_PULSE;	
		
		do { ClearWDT();} while (EDK.sync_level);				// POCKAT NA UKONCENI PULSU - odeslani paketu
		}
	#endif		// INTERFACE_EDK
	
		//******************************
	// vystupni format NETRONIX-RON
	//******************************
 	#ifdef INTERFACE_RSN
        EDK.output |= EDK_OUT_BUZZER;			// terminal ovlada LED+RELE, ctecka pouze pipak
	    EDK.counter.buzzer_time = 6;
		GpioService();	 
  
		Netronix.flag |= FLAG_CARD;				// nastavit flag nactena karta
		EDK.sys_flag &= ~FLAG_READ_CARD;		// zakazat okamzite dalsi cteni karty
	#endif



 #if defined  DEMO_REZIM
		EDK.output |= EDK_OUT_LED_GRN;	
	    EDK.output &= ~EDK_OUT_LED_RED;	
		EDK.counter.led_time = EDK_PRESET_LED_TIME;
	    
		EDK.output |= EDK_OUT_RELAY;			
        EDK.counter.relay = EDK_PRESET_RELAY_TIME;	
	 
	    EDK.output |= EDK_OUT_BUZZER;
		EDK.counter.buzzer_time = 6;
		
		GpioService();	
 #endif
		

}



/*************************************************************************
*Name:		  CardRemoved
*Description: detekovano oddaleni karty
*************************************************************************/
void CardRemoved(void)
{
#if defined INTERFACE_RS

 // v pripade EHS jeste smazat flag 
 if (EDK.input.state & EDK_IN_EHS)
  {
	if (EDK.io_flag & FLAG_EHS_CARD_PRESENCE)		// v pripade ze je karta pritomna
	 {
	   EDK.io_flag &= ~FLAG_EHS_CARD_PRESENCE;		// smazat tento flag aby sem neslo opakovane
       EDK.sys_flag &= ~FLAG_READ_CARD;				// zakaz cteni karty
	   
	   AddReq(PRIORITY_TASK_MID | PROCESS_SCI_STATE_READER, gCard.state, 0);	// odeslat paket 		  
  	 }
  }
 // normalni ctecka
 else			
  {
   // u varianty RS generovat paket oddaleni karty 
   AddReq(PRIORITY_TASK_MID | PROCESS_SCI_STATE_READER, gCard.state, 0);		  
  }

#endif
}


/*************************************************************************
*Name:		  ReadCardId
*Description: cteni karty
*************************************************************************/
void ReadCardId(void)
{
 tUChar temp_cardId[10];							// cislo karty se nacita do docasneho
 													// prostoru v RAM, pokud by se z duvodu chyby cteni
													// nacetla nejaka blbost, napr. same nuly
													// tak se toto cteni nezpracuje - dulezite pro cardRemmoved()


 #ifdef CORE_EDK									// funkce je platna jen pro ctecky 
    unsigned long  tmoutx;
	unsigned char _status, error;
	tUInt i;

	
	gCard.isbusy = 1;									// probiha cteni a odesilani karty
														// flag se smaze po odeslani dat
	gCard.old_state = gCard.state;						// zalohovat stary stav

//**************************************************************************
// v pripade odkladacky je delsi perioda osahavani karty pokud je vlozena
	if (EDK.input.state & EDK_IN_EHS)					
	 {
	   if (EDK.io_flag & FLAG_EHS_CARD_PRESENCE)		// prodlouzena perioda osahavani karty je aktivni
	    {												// jen pokud je detekovana skutecna RFID karta
	     if (EDK.counter.ehs_check_interval==0)			// citac periody osahavani
	      {												// inicilaizovat citac osahavani vlozene karty
 		    EDK.counter.ehs_check_interval = EHS_CARD_INSERTION_TIME;	
			EDK.sys_flag |= FLAG_READ_CARD;				// citac dobehl, povolit jedno nacteni karty
		  }
	    }
	 }



//**************************************************************************
// zalohoat posledni nactene cislo karty, pro porovnani vymeny karty ve sterbine
	if (EDK.input.state & EDK_IN_EHS)	
	 {
	   my_memcpy(&gCard.old_cardId[0], &gCard.cardId[0], sizeof (gCard.cardId) );	
     }
	


//**************************************************************************

	#if (READER_EMMARIN)								// cteni karet Emmarin
	  gCard.state = Emmarin_Read(&gCard.cardId[0]);		// novy stav
	#endif

//**************************************************************************
	
	#if (READER_MIFARE)
	  // je potreba nacist 4 bajty od cardId[1]
	  gCard.state = MifareReadId( &temp_cardId[0]);			// cteni karet Mifare do temp bufferu
	  if (gCard.state == READER_TAG_OK)
	   {
	     my_memcpy(&gCard.cardId[1], &temp_cardId[0], 4);	// zkopirovat cislo karty
	   }													// v pripade uspesneho nacteni 						
	#endif


//**************************************************************************
// pro odkladacku zaveden viceurovnovy buffer na detekci vlozene karty
// protoze odkladacka musi kartu periodicky osahavat, jetli je opravdu vlozena, a neni to nejak osulene
// je potreba osetrit stav, ze vypadne jedno cteni karty a je nespravne toto detekovano jako vytazeni.
// Informaci o vytazeni karty nelze brat z optozavory z duvodu mozneho vlozeni cehokoliv
//**************************************************************************
//!!!pozn:
// jelikoz je kompiler pica, tak to dela nejakou pitomost, v pripade if-else.Proto je podminka IF rozdelena samostatne 2x
  if (EDK.input.state & EDK_IN_EHS)
   {
	 // na prvni vlozeni by to melo reagovat rychleji
	 if (!gCard.ehs_first)
	  {
     	if (!gCard.old_state && gCard.state)
	 	{
       	  gCard.ehs_first = 1;
		  gCard.ehs_buff[0] = 1;
		  gCard.ehs_buff[1] = 1; 
		  gCard.ehs_buff_index = EHS_BUFF_SIZE;
	 	}
	 }
	  
	 if (gCard.ehs_buff_index >= EHS_BUFF_SIZE)			// INTERVAL DETEKCE VSUNUTI
	  {
	    gCard.ehs_buff_index = 0;						// fifo buffer
	
	    // zkontrolovat obsah bufferu jestli jsme nacetli 2 stejne hodnoty, tj. vsunuti karty
		// zaroven ale musi byt aktivovana optozavora, tj. sepnuto=stav 0
	    if ( (gCard.ehs_buff[0]==1) && (gCard.ehs_buff[1]==1) && !(EDK.input.state & EDK_IN_TAMPER) )
	     {			 
		   if (EDK.io_flag & FLAG_EHS_CARD_REMOVED)		// pomocny flip-flop flag, aby se zabranilo
			{											// detekci opakovaneho vlozeni pokud je karta 
			  EDK.io_flag &= ~FLAG_EHS_CARD_REMOVED;	// resetovat flip-flop
			  CardInserted();							// pomalu vytahovana a je v prostoru mezi polem a opto
			  
			  // detekce vymeny karty ve sterbine 		  
			  if ( my_memcmp(&gCard.cardId[0], &gCard.cardId[0], 10) )
			   {
			     gCard.state = 0;
				 CardRemoved();
			   }	
				
			}
	     }
	   	// toto je situace kdy jsou vlozeny 2 karty soucasne, nutno to hlasit 
		// k tomuto se vyuziva hlaseni z emmarin.c rutiny - chyba parity cteni=bitova kolize
		else if ( gCard.ehs_buff[0]==0xff && gCard.ehs_buff[1]==0xff  )
		 {
		   gCard.state = 0;								// INDIKOVAT NEPRITOMNOST KARTY v poli
		   CardRemoved();		
		 }
				
	   	 // zkontrolovat obsah bufferu jestli jsme nacetli 2 stejne hodnoty 
		 else if (( gCard.ehs_buff[0]==0 && gCard.ehs_buff[1]==0  ) ||  (EDK.input.state & EDK_IN_TAMPER))
	  	  {			 
		    CardRemoved();
	  	  }
	  }		// konec if (gCard.ehs_buff_index >= EHS_BUFF_SIZE)
	  
	  gCard.ehs_buff[gCard.ehs_buff_index++] = gCard.state;		// bufferovat stav karty 
   
   }		// konec  if (EDK.input.state & EDK_IN_EHS)


//**************************************************************************
// nejedna se o odkladacku, ale o normalni ctecku
 if (!(EDK.input.state & EDK_IN_EHS))
  {
	// detekce prilozeni karty
   	if ((gCard.old_state == READER_NO_TAG) && (gCard.state == READER_TAG_OK))		// karta prilozena
	 {
	   CardInserted();
     }
 
	// detekce oddaleni karty
   	if ((gCard.old_state == READER_TAG_OK) && (gCard.state == READER_NO_TAG))		// karta oddalena
	 {
	   CardRemoved();
	 }
  }			
//**************************************************************************

	#ifdef INTERFACE_EDK						// pouze v rezimu EDK
	  if (!(EDK.input.state & EDK_IN_WGOUT))	// neplati pokud je vystup WIEGAND
       {
		   EDK.sys_flag &= ~FLAG_READ_CARD;		// zakazat dalsi cteni karty do doby nez se zmeni hrana SYNC signalu
	   }
	#endif
		  
		  
	gCard.isbusy = 0;							// cteni karty ukonceno, povol dalsi cteni, pokud neni blokovano pipakem		  
	  
	  
	#endif		// konec #ifdef CORE_EDK
}
