/*******************************************************************************
 *
 *  Module:         emergency_card.c
 *  Description:    sprava master karet - offline rezim bez terminalu
 *
 ******************************************************************************/

#include "includes.h"

tsOffCard	 gOffCard;
extern tUChar ramBuffer[RAM_BUFFER_SIZE];
extern tUChar inputTable[MAX_SENSORS][INPUT_TABLE_RAM_SIZE];

// PRO POUZITI MASTER KARET JE NUTNE DEFINOVAT GLOBALNE V KOMPILERU MAKRO
//define USE_MASTER_CARDS

/************************************************************************************/
// GetMaxIndex()
// return: vraci maximalni mozny pocet zaznamu ktere se vlezou do dostupne pameti
/************************************************************************************/
tUInt GetMaxIndex(void)
{
#ifdef USE_MASTER_CARDS

 tUInt  mem_size;			// celkova velikost pameti	
 tUChar index_size;			// velikost jednoho zaznamu
 tUChar max_index;			// kolik se vleze do pameti zaznamu
  
 // nejdrive nalezt volne misto v pameti
  mem_size = STRUCT_DEFCARD_SIZE;
  index_size = sizeof(gOffCard);
  max_index = mem_size/index_size;

 return (max_index);

#endif
}



/************************************************************************************/
// WriteEmergencyCard
// ulozi Master kartu do DataFlash
// parametr udava pozici v pameti ma kterou kartu zapsat
// PIN je voliteny parametr - doplnkova ochrana pinem - zatim neimplementovano
// position - je pozice v pameti karet (offset 0-9 pro 10 karet)
// pro snadnejsi a jednoznacny pristup je pamet karet predformatovana pri mazani
// formatuje se pouze index zaznamu, vse ostatni musi zustat 0xFF kvuli naslednemu prepisu
// bajty ktere nejsou 0xFF NELZE PREPSAT!
/************************************************************************************/
unsigned int WriteEmergencyCard(tUChar *UID, tUInt PIN, tUChar position)
{
#ifdef USE_MASTER_CARDS
 
 tUChar current_index;					// aktualni index nalistovaneho zaznamu
 tUChar max_index;						// kolik se vleze do pameti zaznamu
 tUInt temp;
 tUChar status;  
 tsOffCard *ptr;						// pointer na strukturu


  current_index = 0;					// inicializovat citac prvni zaznam     
  max_index = GetMaxIndex();			// zjisti kolik zaznamu je mozne ulozit do pameti 
  ptr = CDATAADDRESS_DEFCARD;			// nastavit na zacatek pameti
  
   
// pozadavek na zapis mimo dostupnou oblast pameti nebo definovany max. pocet zaznamu
  if ((position > max_index) || (position > MAX_NUMBER_EMERGENCY_CARDS))		
   {									
	 return(-1);						// vraci chybu
   }

// nalistovat danou pametovou pozici
  while (ptr->index != position)		// hledat pozadovany index zaznamu
   {									// index je vytvoren pri formatovani prostoru
	 current_index = ptr->index;		// vzit pouzity index z pameti 
     
	 if (current_index >= max_index)	// osetreni ze by se neco pokazilo
	  {
	 	return(-1);						// vraci chybu
	  }
     ptr++;								// nalistovat dalsi zaznam
   }

// obnovit index pro zapis
  gOffCard.index =  ptr->index;		

// na danou pozici zapsat cislo karty 4 bajty
  gOffCard.Id[0] = *(tUChar*)&UID[0];	
  gOffCard.Id[1] = *(tUChar*)&UID[1];		
  gOffCard.Id[2] = *(tUChar*)&UID[2];		
  gOffCard.Id[3] = *(tUChar*)&UID[3];		

// zapis PIN kodu
  gOffCard.Pin[0] = PIN&0x00FF;	
  gOffCard.Pin[1] = (PIN&0xFF00)>>8;	
  
// spocitat crc bloku - pocita se bez CRC
  temp = crc16_ccitt( (unsigned char *)&gOffCard, sizeof (gOffCard)-2);						
  gOffCard.crc = (tUChar)((temp & 0x00ff)^(temp>>8));

// ulozi zaznam  
  status = Write_n_EEPROM ( *(unsigned int*)&ptr, (tUChar*)&gOffCard,  sizeof(gOffCard));  	
  
  if(status != NO_ERROR) 
   {
	   return (-1);			// navratovy kod
   }

  return (NO_ERROR);

#endif  
}



/************************************************************************************/
// RreadEmergencyCard
// nacte z dane pozice ulozenou kartu vcetne pinu
// position - je pozice v pameti karet (offset 0-9 pro 10 karet)
/************************************************************************************/
unsigned int ReadEmergencyCard(tUChar *UID, tUInt *PIN, tUChar position)
{
#ifdef USE_MASTER_CARDS

 tUChar current_index;					// aktualni index nalistovaneho zaznamu
 tUChar max_index;						// kolik se vleze do pameti zaznamu
 tUInt temp;
 tUInt status;  
 tsOffCard *ptr;						// pointer na strukturu
 

  current_index = 0;					// inicializovat citac prvni zaznam     
  max_index = GetMaxIndex();			// zjisti kolik zaznamu je mozne ulozit do pameti 
  ptr = CDATAADDRESS_DEFCARD;			// nastavit na zacatek pameti
  
   
// pozadavek na cteni mimo dostupnou oblast pameti nebo definovany max. pocet zaznamu
  if ((position > max_index) || (position > MAX_NUMBER_EMERGENCY_CARDS))		
   {									
	 return(-1);						// vraci chybu
   }

// nalistovat danou pametovou pozici
  while (ptr->index != position)		// hledat pozadovany index zaznamu
   {									// index je vytvoren pri formatovani prostoru
	 current_index = ptr->index;		// vzit pouzity index z pameti 
     
	 if (current_index >= max_index)	// osetreni ze by se neco pokazilo
	  {
	 	return(-1);						// vraci chybu
	  }
     ptr++;								// nalistovat dalsi zaznam
   }

// nacist ulozena data z dane pozice
  my_memcpy (&gOffCard.index, (void*)ptr, sizeof (gOffCard));

// vratit nactene data
// cislo karty 4 bajty
  *(tUChar*)&UID[0] = gOffCard.Id[0];	
  *(tUChar*)&UID[1] = gOffCard.Id[1];		
  *(tUChar*)&UID[2] = gOffCard.Id[2];		
  *(tUChar*)&UID[3] = gOffCard.Id[3];		

// PIN kodu  
  *PIN = (gOffCard.Pin[0]&0x00ff) | (gOffCard.Pin[1]<<8);	

  return (NO_ERROR);			// navratovy kod OK

#endif
}



/************************************************************************************/
// EmergencyCardIsEmpty
// zkontroluje jestli na dane pametove pozici je neco ulozeno
// index 0-9
/************************************************************************************/
unsigned int EmergencyCardIsEmpty(tUChar position)
{
#ifdef USE_MASTER_CARDS
 
 tUChar current_index;			// aktualni index nalistovaneho zaznamu
 tUChar max_index;				// kolik se vleze do pameti zaznamu
 tsOffCard *ptr;				// pointer na strukturu
   
  max_index = GetMaxIndex();	// zjisti kolik zaznamu je mozne ulozit do pameti 
 
// pozadavek na kontrolu mimo dostupnou oblast pameti nebo definovany max. pocet zaznamu
  if ((position > max_index) || (position > MAX_NUMBER_EMERGENCY_CARDS))		
   {									
	 return(FALSE);						// vraci chybu
   }
   
// nalistovani pozadovaneho zaznamu a kontrola CRC bajtu jestli je zde neni ulozeno
  ptr = CDATAADDRESS_DEFCARD;		// nastavit na zacatek seznamu 
	   
  while (ptr->index != position)
   {
	 current_index = ptr->index;		// vzit pouzity index z pameti 
     
	 if (current_index >= max_index)	// osetreni ze by se neco pokazilo
	  {
	    break;
	  }
	 ptr++;								// nalistovat dalsi zaznam
   }

// je nalistovana pozice volna?
  if (ptr->crc == 0xff)					// hledat prvni volnou pozici - neni ulozeno crc
   {
     return(TRUE);
   }

  return (FALSE);						// pametova pozice je jiz obsazena, neni volna

#endif
}



/************************************************************************************/
// CheckEmergencyAccess
// overi jestli nactena karta ze ctecky je v pameti master karet
// vstup: *card: pointer na buffer s cislem karty ktere overujeme
/************************************************************************************/
unsigned int CheckEmergencyAccess(tUChar *card)
{
#ifdef USE_MASTER_CARDS

 tUChar current_index;						// aktualni index nalistovaneho zaznamu
 tUChar max_index;							// kolik se vleze do pameti zaznamu
 
  max_index = GetMaxIndex();				// zjsiti kolik zaznamu je mozne ulozit do pameti 

  current_index = 0;						// inicializovat citac prvni zaznam
  tsOffCard *ptr;							// inicializovat pointer na strukturu
  ptr = CDATAADDRESS_DEFCARD;				// nastavit na zacatek pameti
  
	
  while (ptr->index != 0xff) 				// prochazet pouze zapsany prostor
   {										// pokud je konec prostoru je index 0xff
	current_index = ptr->index;				// vzit pouzity index z pameti 

	if (!my_memcmp( &(ptr->Id[0]), &card[0], 4))	// karta nalezena v pameti - porovnat UID 4 bajty 
     {
	   return (TRUE);						// navratova hodnota OK
	 }

	ptr ++; 								// karta jeste nenalezena, prochazet pamet dal

    if (current_index >= max_index)			// osetreni konce pameti
	 break;
   }

 return (FALSE);							// karta nenalezena

#endif
}


/************************************************************************************/
// FormatCardMemory
// predformatuje prostor pro Master karty - funkce se vola po predchozim smazani bloku
// formatSize udava pocet zaznamu 1-128
/************************************************************************************/
unsigned int FormatCardMemory(tUChar formatSize)	
{
#ifdef USE_MASTER_CARDS

 tUChar current_index;					// aktualni index nalistovaneho zaznamu
 tUChar max_index;						// kolik se vleze do pameti zaznamu
 tUChar status;
 tsOffCard *ptr;						// inicializovat pointer na strukturu
  
   
  max_index = GetMaxIndex();						// zjisti kolik zaznamu je mozne ulozit do pameti 

  if ((formatSize>max_index) || (formatSize==0))	// na pozadovany pocet zaznamu nelze pamet naformatovat
   {
	 return(-1);
   }

  ptr = CDATAADDRESS_DEFCARD;				// nastavit na zacatek pameti
  current_index = 0;						// inicializovat citac prvni zaznam - offset od 0
    
  while (current_index != formatSize)		// formatovat pocet zaznamu, zapise index - jeden bajt
   {
  	ClearWDT();
	
	status = Write_n_EEPROM ( *(unsigned int*)&ptr, (tUChar*)&current_index, 1);  	
  	
	if (status != NO_ERROR)					// chyba zapisu
	 {
	   return (-1);							// ukoncit cyklus
	 }
	
	current_index++;						// cislovani indexu je od 0 vzestupne
    ptr ++; 								// pointer ukazuje na pametovou pozici dasliho zaznamu
   }

  return (NO_ERROR);						// Zapis OK

#endif
}
   


/************************************************************************************/
// ClearAllEmergencyCards
// smaze z pameti vsechny ulozene Master karty
/************************************************************************************/
//todo...
// tohle je jeste puvodni funkcionalita, kdz se rovnou pristupuje do dataFlash
// ale je to potreba zmenit na uroven RamBufferu a pak to cele zapsat do dataFlash jako celou stranku vcetne Inputconfigurace

unsigned int ClearAllEmergencyCards(void)
{
#ifdef USE_MASTER_CARDS

  tUChar status;

//**************************************************************************  
  // zalohovat do ramBufferu nasledujici obsah, ktery je pak potreba obnovit
  Read_n_EEPROM ( CDATAADDRESS_INPUTTABLE, (tUChar*)&ramBuffer, STRUCT_INPUTTABLE_SIZE);
//**************************************************************************  
  
  
  status = ClearDF(BLOCK_B);
  if (status == NO_ERROR)
   {
	// predformatovat prostor pameti - zapsat indexy, tim je dana celkova velikost kolik lze zapsat karet
	status = FormatCardMemory(MAX_NUMBER_EMERGENCY_CARDS);		// predformatovat pametovy prostor 
	if (status != NO_ERROR)
	 {
	  return (-1);		// chyba formatovani
	 }
  }
  else
   {
     return (-1);		// nejaka chyba
   }

  //**************************************************************************  
  // todo... dodelat
  // obnovit obsah configurace kterou jsme predtim smazali
  //**************************************************************************  
  status = Write_n_EEPROM( CDATAADDRESS_INPUTTABLE, (tUChar*)&ramBuffer, STRUCT_INPUTTABLE_SIZE );

  return (NO_ERROR);		// funkce ukoncena OK

#endif
}


/************************************************************************************/
// RemoveEmergencyCard
// smaze z pameti kartu na dane pozici - nutno provest pres buffer s celym prostorem
/************************************************************************************/
unsigned int RemoveEmergencyCard(tUChar position)
{
#ifdef USE_MASTER_CARDS

  tUChar current_index;					// aktualni index nalistovaneho zaznamu
  tUChar max_index;						// kolik se vleze do pameti zaznamu
  tUInt  temp;
  tUChar status;  
  tUChar pos_count=0;	
  
  tsOffCard *ptr;						// pointer na strukturu
  tsOffCard *ptrRAM;					// pointer do RAM bufferu

  current_index = 0;					// inicializovat citac prvni zaznam     
  max_index = GetMaxIndex();			// zjisti kolik zaznamu je mozne ulozit do pameti 
  
  ptr = CDATAADDRESS_DEFCARD;			// nastavit na zacatek pameti - source
  ptrRAM = &ramBuffer[0];				// nastavit na zacatek pameti RAM - destination
   
// pozadavek na kontrolu mimo dostupnou oblast pameti nebo definovany max. pocet zaznamu
  if ((position > max_index) || (position > MAX_NUMBER_EMERGENCY_CARDS))		
   {									
	 return(-1);						// vraci chybu
   }


// nejdrive zalohovat cely prostor emergency kater - pamet DATAFLASH
// modifikace=ERASE+WRITE, prepis pam.bunek neni mozny
  while ((pos_count < max_index) && (pos_count < MAX_NUMBER_EMERGENCY_CARDS))		// osetreni rozsahu 
   {
	 my_memcpy( (void*)ptrRAM, (void*)ptr, sizeof (gOffCard));		// zkopirovat jeden zaznam do RAM bufferu

   	 ptr++; 									// prejit na dalsi zaznam
	 ptrRAM++;									// dalsi zaznam v RAM bufferu
	 pos_count++;								// citac indexu
   }

//************************************************
// prostor emergency karet je zazalohovan v RAM
// nasleduje odebrani pozadovaneho indexu z RAM bufferu, smazani stranky DATAFLASH a znovu vypaleni
//************************************************
 
// smazat blok DATAFLASH a predformatovat pamet
  status = ClearAllEmergencyCards();
  if (status != NO_ERROR)
   {
     return (-1);						// chyba mazani
   }
	 
// nalistovat pozadovany zaznam - index nutno ponechat! nemazat
  ptrRAM = &ramBuffer[0];				// inicializovat pointer na zacatek RAM bufferu
  while (ptrRAM->index != position)		// hledat pozadovany index zaznamu
   {									// index je vytvoren pri formatovani prostoru
     ptrRAM++;							// nalistovat dalsi zaznam
   }

// smazat obsah ID
	ptrRAM->Id[0] = 0xFF;
	ptrRAM->Id[1] = 0xFF;
	ptrRAM->Id[2] = 0xFF;
	ptrRAM->Id[3] = 0xFF;

// smazat obsah PIN
	ptrRAM->Pin[0] = 0xFF;
	ptrRAM->Pin[1] = 0xFF;

// smazat obsah CRC
	ptrRAM->crc = 0xFFFF;



// zapis zpet do DATAFLASH - zapisuje se zaznam po zaznamu dokud se nenalezne posledni polozka
  ptrRAM = &ramBuffer[0];			// source - nastavit na zacatek RAM bufferu
  ptr = CDATAADDRESS_DEFCARD;		// destination - dataflash
  pos_count = 0;					// inicializovat citac
  
  while ((pos_count < max_index) && (pos_count < MAX_NUMBER_EMERGENCY_CARDS))				// osetreni rozsahu zapisu
   {
  	 ClearWDT();
	 
	 status = Write_n_EEPROM ( (tUInt)ptr, (tUChar*)ptrRAM,  sizeof(gOffCard));  	// zapis jednoho zaznamu
     wait_ms(5);			// nutno pockat
	   
	 if (status != NO_ERROR)
	  {
		return (-1);							// chyba zapisu, vypadnout s chybou
	  }

   	 ptr++; 									// predchozi zapis OK, prejit na dalsi zaznam
 	 ptrRAM++;									// dalsi zaznam v RAM bufferu
	 pos_count++;								// citac indexu
   }

  return (NO_ERROR);			

#endif  
}


/************************************************************************************/
// CardMemoryIsFormated
// overi jestli je pamet karet predformatovana - predpoklada se uplne vymazani cipu
// pro jistotu se projdou vsechny pam.pozice jestli je nastaven prvni bajt
/************************************************************************************/
tUInt CardMemoryIsFormated(void)
{
#ifdef USE_MASTER_CARDS

  tsOffCard *ptr;				// pointer na strukturu
  tUChar pos_count=0;			// citac pozice
  tUChar max_index;				// kolik se vleze do pameti zaznamu
      

  ptr = CDATAADDRESS_DEFCARD;	// nastavit na zacatek pameti
  max_index = GetMaxIndex();	// zjisti kolik zaznamu je mozne ulozit do pameti 
  
  // projiti dostupneho prostoru a kontrola jestli je spravne predformatovan  
  while ((pos_count < max_index) && (pos_count < MAX_NUMBER_EMERGENCY_CARDS))	// osetreni rozsahu zapisu
  {
    if (ptr->index != pos_count)
	 return (FALSE);			// kontrola prvniho bajtu, pokud neni formatovano je 0xFF
    ptr++;						// pokud neodpovida vzestupnemu indexu je to taky chyba
	pos_count++;				// citac indexu
  }

 return (TRUE);					// OK, naformatovano

#endif
 
} 



/************************************************************************************/
// CardMemoryIsEmpty
// overi jestli je pamet karet prazdna - neni ulozena zadna karta
/************************************************************************************/
tUInt CardMemoryIsEmpty(void)
{
#ifdef USE_MASTER_CARDS

 tUInt index;
 tUInt state;
 
 for (index = 0; index < MAX_NUMBER_EMERGENCY_CARDS; index++)
  {
    state = EmergencyCardIsEmpty(index);	// projit cely prostor
	if (  state != TRUE)					// neni pozice volna?
     {
	   return (FALSE);						// vratit stav
	 }
  }
 return (TRUE);

#endif
}
