/******************************************************************************
*	F u n c t i o n . c
*
*
*
*
*******************************************************************************/
 
#include "includes.h"


extern tUChar ramBuffer[RAM_BUFFER_SIZE];	// globalni buffer
tsConstant 	cfgsystem; 			// prostor v RAM pro strukturu CONSTANT
tsTitle		cfgstitle;			// prostor v RAM pro strukturu TITLE


// --------------------------------------------------------------------------------------------
// seriove cislo jednotky je pracovne ulozeno v DATAFLASH ROM
// zalozni kopie je ulozena zde na zacatek bloku ROM, pro pripad obnovy po smazani DATAFLASH
// obnova zatim nedoresena
// --------------------------------------------------------------------------------------------
#define SNCONST_ROM_ADDRESS				0x8000					// zde je mapovano SNCONST v ROM
const char snConst[12] __attribute__ ((section (".snconst"))) =
 {
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,   // seriove cislo jednotky - default je 0xFF
 };

const char CONST_MANUF_STRING[16] = { MANUF_STRING};



 
 	
/******************************************************************************
//	UART_ClearErrors
//
//  osetreni zatuhnuti UARTU
******************************************************************************/
void UART_ClearErrors(void)
{
  tUInt	 temp;
   
  if(u0rbh) 	 		// chyba UARTU
   {
     re_u0c1 = 0;   	// Reception disabled
     temp = u0rbl;		// vycist registr
     re_u0c1 = 1;   	// Reception enabled
   }
}	 
		  

   
   
/******************************************************************************
*	E m p t y F u n c
*
*
* The Empty function for no task in the list
*
******************************************************************************/
void EmptyFunc(void)
{
 return; 
}

  

/******************************************************************************
* read_Oper
*
******************************************************************************/
#if defined CORE_EDK || defined CORE_POW
tUChar read_Oper()
{
   tUChar status;
   
   EEPROM.address = CDATAADDRESS_OPERATIVE;

   status = Read_n_EEPROM( EEPROM.address , (unsigned char*)&OPER, sizeof(OPER));
   if( status != NO_ERROR)
    {
	 appCB.error = ERR_EEPROM_READ;
	 appCB.error |= ERR_FATAL;			// kriticka chyba
	 ErrorService();
	 while(1); 
	}

return(NO_ERROR);	
}
#endif



/******************************************************************************
* write_Oper
*
******************************************************************************/
#if defined CORE_EDK || defined CORE_POW
tUChar write_Oper()
{
   tUChar status;
   
   EEPROM.address = CDATAADDRESS_OPERATIVE;

   status = Write_n_EEPROM ( EEPROM.address , (unsigned char*)&OPER, sizeof(OPER));
   if(status != NO_ERROR)
    {
	  appCB.error = ERR_EEPROM_WRITE;
	  appCB.error |= ERR_FATAL;	// kriticka chyba
	  ErrorService();
	  while(1); 
	}

   // aktualizovat vzdy hodnotu v CORE
    DataAddrSet(OPER.idAdr);

return(NO_ERROR);	
}
#endif



/******************************************************************************
// Zapis S/N do FLASH, 6 bajtu
//
******************************************************************************/
#if defined CORE_EDK || defined CORE_POW
tUInt WriteSn(unsigned char* buff)
{
  tUInt status;
  tUChar loop;
  

  // pro operace zapis/cteni z dataflash se pouziva odkladaci RAM buffer
  my_memcpy(&ramBuffer[0], (tUChar*)SNCONST_ADDRESS, BLOCK_A_ALLOC_SIZE );	// zkopiruje obsah dataflash do RAM bufferu

  status = ClearDF(BLOCK_A);	// ted smazat celou stranku DATAFLASH
  if (status) 
  return (-1);					// nepovedlo se smazat stranku, vypadnout s chybou

  // zkopirovat SN pro zapis do RamBufferu	
  my_memcpy( &ramBuffer[0], &buff[0], 12);
  

  // SN ulozit do DataFlash
  status = Write_n_EEPROM( DF_BLOCK_A_START, (tUChar*)&ramBuffer[0], BLOCK_A_ALLOC_SIZE);	  	// zapsat zpet cely BLOCK_A
  if (status != NO_ERROR) 
   return (-1);																	// nepovedlo se zapsat, vypadnout s chybou   

 
  // ZAPSAT zalohu SN i do ROM, odtud se bude provadet obnova, pokud bude potreba
  // pokud zapis neprojde, tak to znamena ze je jiz SN zapsano
  status = Write_n_EEPROM( SNCONST_ROM_ADDRESS, (tUChar*)&ramBuffer[0], 12);	// zapsat jen SN
  if (status != NO_ERROR) 
   return (-1);																	// nepovedlo se zapsat, vypadnout s chybou   

  
  return (NO_ERROR);
}		   
#endif


  


/******************************************************************************
// RestoreSN
// obnovi SN v Dataflash, zalohou z ROM
******************************************************************************/
/*#if defined CORE_EDK || defined CORE_POW
tUInt RestoreSN(unsigned char* buff)
{
  tUInt status;
  tUChar loop;
  
  // pro operace zapis/cteni z dataflash se pouziva odkladaci RAM buffer
  my_memcpy(&ramBuffer[0], (tUChar*)SNCONST_ADDRESS, BLOCK_A_ALLOC_SIZE );	// zkopiruje obsah dataflash do RAM bufferu

  status = ClearDF(BLOCK_A);	// ted smazat celou stranku DATAFLASH
  if (status) 
  return (-1);					// nepovedlo se smazat stranku, vypadnout s chybou

  // zkopirovat SN pro zapis do RamBufferu	
  my_memcpy( &ramBuffer[0], &buff[0], 12);
  

  // SN ulozit do DataFlash
  status = Write_n_EEPROM( DF_BLOCK_A_START, (tUChar*)&ramBuffer[0], BLOCK_A_ALLOC_SIZE);	  	// zapsat zpet cely BLOCK_A
  if (status != NO_ERROR) 
   return (-1);																	// nepovedlo se zapsat, vypadnout s chybou   

 
  // ZAPSAT zalohu SN i do ROM, odtud se bude provadet obnova, pokud bude potreba
  // pokud zapis neprojde, tak to znamena ze je jiz SN zapsano
  status = Write_n_EEPROM( SNCONST_ROM_ADDRESS, (tUChar*)&ramBuffer[0], 12);	// zapsat jen SN
  if (status != NO_ERROR) 
   return (-1);																	// nepovedlo se zapsat, vypadnout s chybou   

  
  return (NO_ERROR);
}		   
#endif

*/


  
/*******************************************************************************/
// hex2ascii - konverze 2 bajtovy HEX na ASCII
/*******************************************************************************/
tUChar lookup[] = { '0', '1', '2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; 

char toAscii(unsigned char n)
{
  
  return lookup[n&0x0f];
}

	

/******************************************************************************
* system_Read
* read_n_EEPROM() vraci 1 jako OK, vse ostatni je chyba
******************************************************************************/
#if defined CORE_EDK || defined CORE_POW
tUChar system_Read( void )
{
  unsigned char cSts;

   cSts = Read_n_EEPROM (CDATAADDRESS_CONSTANT , (unsigned char *)&cfgsystem, (short)sizeof( tsConstant));   // nacti celou strukturu cfgsystem
   return( cSts );
}


/************************************************************************************/
// WriteMAC
// zapis MAC adresy
/************************************************************************************/
tUChar WriteMAC( void )
{
  tUInt status;

  // operace zapisu musi byt READ-MODIFY-WRITE, proto bufferovat
  // nacitame cely alokovany prostor DATAFLASH BLOCK_A
  Read_n_EEPROM ( DF_BLOCK_A_START, (tUChar*)&ramBuffer, BLOCK_A_ALLOC_SIZE);	

  // pridat nove data do RamBufferu 
  my_memcpy ((tUChar*)&ramBuffer+sizeof(cfgsystem.tsn), (tUChar*)&cfgsystem.MACadr, sizeof(cfgsystem.MACadr));	

  // smazat obsah DF block_A
  ClearDF(BLOCK_A);
 
  // zapsat zpet do DF    
  status = Write_n_EEPROM ( DF_BLOCK_A_START, (tUChar*)&ramBuffer, BLOCK_A_ALLOC_SIZE );

  // aktualizovat strukturu Config
  ReadConfig();

	  
  return (status);					// navratovy kod
}
  
#endif
  


/******************************************************************************
* SnIsInitialized
*
******************************************************************************/
tUInt SnIsInitialized(void)
{
  tUChar i;
  tUChar *p_src;
  
  p_src = SNCONST_ADDRESS;
	 
  for (i=0; i<6; i++)
   {
     if ( *(p_src+i) == 0xFF )
      {
	    return (FALSE);	// neco vetsiho nez povoleny rozsah
	  }
   }
   
  return (TRUE);		// spravne cislo
}


tUInt typ3, typ,typ5,mac;	 
tUChar pc1, pc2;
tUInt pc;

/******************************************************************************
// Zapise konstanty do EEPROM - SN. Bootver, atd.. 
/******************************************************************************/
#if defined CORE_EDK || defined CORE_POW
tUChar InitConst(tUChar iflag) 
{
   tUChar i;
   tUChar *p_src, *p_dst;
   tULong temp;
   tUChar status;
   
// nacteni struktury cfgsystem 
   status = system_Read();		
   if( status != NO_ERROR) 		
	{								
	  appCB.error |= ERR_FATAL;		// kriticka chyba
	  ErrorService();				// zablokovat beh a blikat LED
	  while(1);  
	}

  
   // kontrola jestli SN je same 0xFF - neni inicializovany stav, v tom pripade nema smysl cislo prevadet do ASCII
   if ( SnIsInitialized() == TRUE)
    {
 	  // prekopiruje SN z ROM do RAM
      p_src = SNCONST_ADDRESS;
	  p_dst = (unsigned char *)&cfgsystem.tsn;
  
   	  // prevest SN z HEX do ASCII a prekopirovat
	  for (i=0; i<6; i++)
       {
	    *p_dst = ascii2hex(*p_src, *(p_src+1) );
	     p_src+=2;
	     p_dst++;
	   }
	

  	  // doplnit identifikacni data z konstant
   	  cfgsystem.master   = MASTER_ID;	
   	  cfgsystem.bootver  = BOOTVER_ID;
   	  cfgsystem.manufact = MANUF_ID;
      cfgsystem.rez1 = 0;
  
  
      // --------------------------------------------
	  // GENEROVANI MAC ADRESY PODLE DOKUMENTU 2016
	  // --------------------------------------------
	  
	  // kod zarizeni
	  p_src = SNCONST_ADDRESS+6;				
	  typ = my_atol(p_src, 2);			// prevest z dec tvaru na binarni char
	  typ3 = (typ&0x07)+1;				// vzit 3 spodni bity z typu +1
	  typ5 = (typ&0xf8)>>3;				// vzit 5 hornich bitu z typu zarizeni
  
	  // poradove cislo
	  p_src = SNCONST_ADDRESS+8;				
	  pc = my_atol(p_src,4);			// prevest z dec tvaru na binarni long

	  // vypocet MAC adresy poddle klice typ3*pc*typ5
	  mac = typ3*pc*typ5;	

   	  // vygeneruje MAC adresu
	  cfgsystem.MACadr[0] = mac;		// generovana polozka MAC, s touto se primo nepracuje, je to generovany mustr
	  
	  
   	  // pokud je predan tento flag, tak aktualizovat adresy = inicializace
	  if(iflag)
       {
      	 cfgsystem.MACadr[1] = cfgsystem.MACadr[0];		// pracovni polozka adresy MAC
      	 cfgsystem.MACadr[2] = cfgsystem.MACadr[0];		// kopie pracovni MAC pro pripad zjistene kolize a zmeny pracovni MAC
       }	

    // zapis do EEPROM
	status = WriteMAC();	
	
    // vzit vygenerovanou pracovni MAC adresu
	OPER.idAdr = cfgsystem.MACadr[0];
 	
	// akrualizovat structuru Config
	system_Read();

    // aktualizovat vzdy hodnotu v CORE
    DataAddrSet(OPER.idAdr);

   } // konec if ( SnIsInitialized() == TRUE)
   

     return(NO_ERROR);
}
#endif




/******************************************************************************
* CfgConstIsInitialized 
*
******************************************************************************/
#if defined  CORE_EDK || defined CORE_POW
tUInt CfgConstIsInitialized(void)
{
  tUChar status;

  EEPROM.address = CDATAADDRESS_OPERATIVE;

  if( (Read_n_EEPROM( EEPROM.address , (unsigned char*)&OPER, sizeof(OPER))) != NO_ERROR )
    {
	 appCB.error = ERR_EEPROM_READ;
	 return(FALSE);
	}
	 
  // pokud souhlasi kontrolni bajt, je ulozena inicializace platna
  if ( OPER.cfgDone == CFG_CHECK_BYTE)
   return (TRUE);
  else
   return (FALSE);
}
#endif



/******************************************************************************
// Write_CFG_DONE
// zapise kontrolni bajt
******************************************************************************/
tUInt Write_CFG_DONE(void)
{
 OPER.cfgDone = CFG_CHECK_BYTE;	// kontrolni bajt 
 write_Oper();							// zavolat funkci pro zapis struktury OPER
}


/******************************************************************************
// zapise do dataflash default hodnoty
/******************************************************************************/
tUInt InitConfig(void)
{		
  tUInt status;
  
  my_memset(&OPER.appcfg, 0, sizeof(OPER));	// vymazani prostoru OPER

  OPER.idAdr = DEFAULT_UNIT_ADDRESS;		// docasne pridelena adresa zarizeni
	  
  OPER.cfgDone = CFG_CHECK_BYTE;			// kontrolni bajt 
 
  status = ClearDF(BLOCK_A);				// ted smazat celou stranku DATAFLASH
 
  Write_RomTitle(CONST_MANUF_STRING);		// ulozi default popisku zarizeni

  write_Oper();								// ulozi adresu do DataFlash
		

//----------------------------------------------------------------
// naformatovat prostor EMERGENCY KARET pokud neni inicializovan
// plati pouze pro variantu RS
//----------------------------------------------------------------
  #ifdef INTERFACE_RS  
    if (CardMemoryIsFormated() != TRUE)	// vraci chybu, pokud neni formatovano
     {
       ClearAllEmergencyCards();
     }
 #endif
	
   // musi byt az po ClearAllEmergencyCards	  
	InitInputTable();						// inicializace InputTable v DataFlash
	  	
  return (status);
}


		
/******************************************************************************
*	I n i t A P P
*
*
* The function initialized the HW and application
*
******************************************************************************/
#if defined  CORE_EDK || defined CORE_POW
tUInt InitAPP(void)
{
  tUInt status;
  tULong *lptr;
  
    //-----------------------------------
	//	inicializace OPER v dataflash
    //-----------------------------------

	if ((CheckAPP() == EE_NO_MAC_ADDR) || (CfgConstIsInitialized() == FALSE))
	 { 												
		status = InitConfig();
		
		// ted se zkontroluje jestli nahodou nedoslo ke smazani konfigurace a SN v dataflash bloku_A
		lptr = &snConst[0];
		if ( *lptr != 0xFFFFFFFF)				// pokud existuje v ROM SN
		 {
		   WriteSn( (tUChar*)&snConst[0]);		// tak jej obnovit do DataFlash, inicializace vseho pak probehne sama
		 }
		
	 }


    // vymazani prostoru OPER pred znovunactenim
	my_memset(&OPER.idAdr, 0, sizeof(OPER));		

    read_Oper();

    DataAddrSet(OPER.idAdr);	// aktualizovat MAC adresu, nejdrive defaultni, 
								// pokud je generovana MAC adresa tak se aktualizuje dale v InitConst()
	
	Read_RomTitle(); 			// nacteni textove popisky zarizeni

	//--------------------------------------------
	// pokud globalni konfigurace neni pritomna 
	// tak inicializovat vychozi tovarni nastaveni     
	//--------------------------------------------
    ReadConfig();				// nacteni globalni konfigurace	

	if (EDK.config.check_byte != 0xAA)	
     {
       status = SetDefaultConfig();				
	 }

	  
	return (status);
}
#endif



/******************************************************************************
* CheckAPP
*
******************************************************************************/
#if defined CORE_EDK || defined CORE_POW
tUChar CheckAPP(void)
{
	tUChar status;
	
	status = read_Oper();
	if( status != NO_ERROR) 		
	 {								
	   appCB.error |= ERR_FATAL;	// kriticka chyba
	   ErrorService();				// zablokovat beh a blikat LED
	   while(1);  
	 }

	if ((OPER.idAdr == 0xFFFF) || (OPER.idAdr == 0))
	 {
   	  return (EE_NO_MAC_ADDR);		// MAC adresa neni jeste zapsana
 	 }

  return (EE_MAC_ADDR_OK);			// MAC adresa pritomna, cip je jiz inicializovan

}
#endif



/******************************************************************************
// c r e a t e M A C
//
// nacte MAC adresu z MACadr[1] a pak zkopirovat do struktury OPER
******************************************************************************/
/*#if defined CORE_EDK || defined CORE_POW
void createMAC( void )
{
	constant C;

    Read_n_EEPROM ( CDATAADDRESS_CONSTANT , &C, sizeof(constant) );
    
	if ( C.MACadr[1] == 0xFFFF)
	  OPER.idAdr = DEFAULT_BOOT_UNIT_ADDRESS;
	else
	  OPER.idAdr = C.MACadr[1];
}
#endif
*/

/******************************************************************************
// r e s t o r e M A C
//
// prepise z MACadr[0] adresu do MACadr[1] a MACadr[2]
******************************************************************************/
/*#if defined CORE_EDK || defined CORE_POW
void restoreMAC( void )
{
constant C;

    Read_n_EEPROM ( CDATAADDRESS_CONSTANT , &C, sizeof(constant) );

	if(C.tsn[4] == 0xff && C.tsn[5] == 0xff) 
	  {
		C.MACadr[1] = 0x0101;
		C.MACadr[2] = C.MACadr[1];
		OPER.idAdr = C.MACadr[1];
	  }
	else
	  {
		C.MACadr[1] = C.MACadr[0];
		C.MACadr[2] = C.MACadr[1];
		OPER.idAdr = C.MACadr[1];
	  }

    Write_n_EEPROM ( CDATAADDRESS_CONSTANT , &C, sizeof(constant) );
	  
}
#endif

*/



/******************************************************************************
* Error
*
******************************************************************************/
void ErrorLed(void)
{ 
	Init_TimerE();					// trigger ext. wdt
  	ALL_InterruptEnable;			// pro pripad ze by nebylo jste nastaveno 
	
  while (1)
  {
	wait_ms(100);
	LED_ERROR_FLIP;
  }
}	


/******************************************************************************
// interrupt 
// int0				(software int )
******************************************************************************/
void _int0(void) __attribute__ ((interrupt));
void _int0(void)
{
    ir_int0ic = 0;		// clear flag
}



/******************************************************************************		
// interrupt 
// int1				(software int )
******************************************************************************/
// hardwarove svazano s RX pinem - detekce pritomnosti dat na lince
// pokud by se pouzilo je nutne zakazovat Int1 pred volanim PutBusChar.
void _int1(void) __attribute__ ((interrupt));
void _int1(void)
{
	ir_int1ic = 0;		// clear flag

	BusControl.BusState &= ~BUS_FREE; 					// maze se priznak volne sbernice
	BusControl.Timer_counter = BUS_FREE_TIMEOUT;		// a nuluje se timeout pro znovu nastaveni flagu

}




/******************************************************************************
// interrupt od TRF7960 na INT3
// int3				(software int 26)
******************************************************************************/
void _int3(void) __attribute__ ((interrupt));
void _int3(void)
{
	ir_int3ic = 0;		// clear flag
}


/******************************************************************************
// preruseni od KI0 
//
******************************************************************************/
// input_key			(software int 13)
void _input_key(void) __attribute__ ((interrupt));
void _input_key(void)
{
   ir_kupic = 0;				// clear flag

   ki0pl ^=1;   				// dalsi preruseni od KI0 bude na opacnou hranu
 
   EDK.io_flag ^= FLAG_SYNC_IN;	// flag indikuje prave aktivni hranu signalu SYNC
   


//------------- plati pouze pro rezim EDK, synchronizaci cteni ridi terminal AL --------
#ifdef INTERFACE_EDK
if (!(EDK.input.state & EDK_IN_WGOUT))				// neplati pro rezim WIEGAND
{
	if (!(EDK.input.state & EDK_IN_READER2))	// pokud neni osazen JP4 READER2, tak se ctecka chova jako nadrizena a generuje do IN2 sync pulsy
     {
  	   if (EDK.io_flag & FLAG_SYNC_IN)				// nadrizena ctecka cte Emmarin pokud je SYNC signal na dratu D0 v log.1
	    {
		  EDK.sys_flag |= FLAG_READ_CARD;			// povol cteni karty pokud je SYN log.1
  	    }	
	   else EDK.sys_flag &= ~FLAG_READ_CARD;		// zakaz cteni karty pokud je SYN log.0
	 }
	else										// JP6 JE OSAZEN, ctecka se chova jako podrizena a ceka na IN2=LOG.1 aby mohla spustit cteni emmarinu
	 {
	   if (!(EDK.io_flag & FLAG_SYNC_IN))			// podrizena ctecka cte Emmarin pokud je SYNC signal na dratu D0 v log.0
	    {
		  EDK.sys_flag |= FLAG_READ_CARD;			// povol cteni karty pokud je SYN log.0
		}
	   else EDK.sys_flag &= ~FLAG_READ_CARD;		// zakaz cteni karty pokud je SYN log.1		 
	 }
}
#endif


}



/******************************************************************************
// WDT_Init
//
******************************************************************************/
void WDT_Init(unsigned char _mode)
{
    prcr.byte = 0x02;		// unprotect PM0 and PM1 

	cspro = 1;				// count source protction mode

    // Watchdog function after it times out:0 -(default) generate interrupt,  1  - resets the MCU 
    // 0 (default) - jumps to the watchdog interrupt routine 
    // 1           - resets the MCU 
  	if (_mode == WDT_HARD_RESET)
	 pm12 = 1;
	else
	 pm12 = 0;


    // protect PM1 
    prcr.byte = 0;

    // prescaler is div by 128 watchdog timer period = (32,768 x 128) / (13560)/2 = 154ms perioda  
    wdtc7 = 1;

    // Start Watchdog Timer by writing any value to wdts register (value
    //   always resets to 0x7fff when written to) 
    wdtr.byte = 0x00;
    wdtr.byte = 0xFF;

   // Start WATCHDOG Timer
    wdts.byte = 0xff;
	
	ClearWDT();
	
}


/******************************************************************************
// ClearWDT
//
******************************************************************************/
void ClearWDT(void)
 {
// prepsano do asm, protoze kompiler to zbytecne dramatizuje
	asm ("mov.b	#0x00,0x000d");			//wdtr.byte = 0x00;
  	asm ("mov.b	#0xff,0x000d");			//wdtr.byte = 0xFF; 
    
	ClearExtWDT();
 }			


/******************************************************************************
// ClearExtWDT
//
******************************************************************************/
void ClearExtWDT(void)
{
#if !defined DEBUG
   WDT_PIN ^=1;
#endif
}		


/******************************************************************************
// SwReset
//
******************************************************************************/
void SwReset(void)
{
	prc1 = 1; 
	pm03 = 1;
}


/******************************************************************************
*	ResetService
*   funkce pro zpristupneni resetu z aplikacni vrstvy
******************************************************************************/
void ResetService(void)			
{
  SwReset();
}
	


//==============================================================================
//| BusPutChar(unsigned char Data)
//| function to send one byte over RS485 bus
//| return 0 when done
//| return > 0 when data collision on bus ocurred
//==============================================================================

// nevim jak propojit na existujici definice v "c"
//#define INT_LEVEL_INT1			0x06		// detekce bitu na RXD

#ifdef READER_MIFARE
	#define f1_CLK_SPEED		13560000	// hodnota externiho krystalu pro ctecku MIFARE											
#else
	#define f1_CLK_SPEED		18432000	// hodnota externiho krystalu pro EDK-Emmarin + POW
#endif



//==============================================================================
// pozn. k exaktnimu casovani: interni oscialtor v R8C21336 je natrimovany z
// fabriky s presnosti 1,5% takze co kus to original, proto je na novem HW
// pouzit externi krystal 18.432Mhz. 
//==============================================================================

// plati pouze pro externi krystal 18.432Mhz
#ifdef f1_CLK_SPEED

 #if (f1_CLK_SPEED == 18432000)
  asm(".equ PERIOD_10us,			24");	// delay 10us
  asm(".equ BITPERIOD_0,			133");	// delka bitu 0 - log.1 z MAX485 
  asm(".equ BITPERIOD_1,			 41");	// delka bitu 1 - log.0 z MAX485
  asm(".equ BITPERIOD_START,		134");	// delka start bitu
  asm(".equ BITPERIOD_STOP,			 50");	// delka stop bitu
  asm(".equ STOP_PERIOD,			255");	// pro detekci kolize ve stop bitu
  //asm(".equ SPACE_PERIOD,		   1000");	// prodleva mezi odesilanymi bajty asi 5ms
  asm(".equ SPACE_PERIOD,		   200");	// prodleva mezi odesilanymi bajty asi 1ms

 // plati pro externi krystal 13.56Mhz
 #elif (f1_CLK_SPEED == 13560000)
  asm(".equ PERIOD_10us,			17");	// 
  asm(".equ BITPERIOD_0,			97");	// delka bitu 0 - log.1 z MAX485 
  asm(".equ BITPERIOD_1,			30");	// delka bitu 1 - log.0 z MAX485
  asm(".equ BITPERIOD_START,		98"); 	// delka start bitu
  asm(".equ BITPERIOD_STOP,		     36");	// delka stop bitu
  asm(".equ STOP_PERIOD,			255");	// pro detekci kolize ve stop bitu
  asm(".equ SPACE_PERIOD,		   636");  // prodleva mezi odesilanymi bajty min. 1,5xCHAR = min.800us (nastaveno 1ms)
 #endif
 
#endif



//==============================================================================
// definice navratovych kodu chyb
asm(".equ NO_ERROR,					0x0000");	// bajt odeslan OK
asm(".equ ERROR_BUS_BUSY,			0x0001");	// detekovana obsazena linka
asm(".equ ERROR_STOP_BIT_COLLISION,	0x0002");	// bitova kolize na stop bitu
asm(".equ ERROR_BIT_COLLISION,		0x0003");	// bitova kolize v datovych bitech
	 

/******************************************************************************************/
// BusPutCharAsm()
// function to send one byte over RS485 bus
// return 0 when done
// return > 0 when data collision on bus ocurred
/******************************************************************************************/
// globalni promena pro TXD rutinu
char loop;
/******************************************************************************************/
// rutina zabira 173bajtu, mapovana na konec pameti do sekce .page_f13
// !! nezasahovat, nemenit kod !! 
// !! kriricke misto jsou casovaci smycky, pokud nezacinaji na sude adrese trvají dele !!
// !! v pripade ze se casovani po zasahu do kodu zmeni, staci doplnit "nop" instrukci !!
// !! tak, aby casovaci smycky zacinaly opet na sude adrese
// forma volani funkce prostrednictvim void() je nutna kvuli emulatoru a alokaci do sekce
/******************************************************************************************/
 void BusPutCharAsm (char data);	__attribute__ ((section (".page0f13")))
 	void BusPutCharAsm (char data)				
{
    		asm ("TXD_START:");						
    						asm ("mov.b	r1l, _data");		//vstupni promena - data 

    						asm ("fclr i");					// ALL_InterruptDisable;									
																						
				    		asm ("jsr.a  _ClearWDT");		// ClearWDT();

			    			asm ("bclr	2,0x00a5");			// RECEIVER_DISABLE;
							
			    			asm ("mov.b	#0x01,r0l");		// cnt = 1;					
			    			asm ("btst	0x07,0x00e1");		// if(!VRXD)
    						asm ("jnz	START_BIT");
			    			asm ("mov.w	#ERROR_BUS_BUSY,R0");	// return(3);

			    			asm ("bset	2,0x00a5");			// RECEIVER_ENABLE;

    						asm ("fset i");					// enable interrupts
							asm ("exitd");					// deallocate stack frame

//==============================================================================
			asm ("START_BIT:");
							asm ("bset	6,0x00e1");				// SET_VTXD(1) - generuj start bit = 0 na linku
    					    asm ("mov.b	#BITPERIOD_START,r0h");	// loop = BITPERIOD; 
						    asm ("mov.b	r0l, _loop");			// while( loop ) loop--;
    						asm ("mov.b	r0h,r0l");			
    					
			asm ("START_BIT_LOOP:");
    						asm ("dec.b	r0l");					// loop 
    						asm ("jne	START_BIT_LOOP");
							asm ("mov.b	_loop,r0l");			// cnt 

//==============================================================================
    		asm ("SEND_DATA:");						
							asm ("mov.b	r0l,r0h");				// cnt 
    						asm ("and.b	_data,r0l");			// Data // if( (unsigned char)Data & cnt ) 		 
	   						asm ("jeq	SEND_0");

			asm ("SEND_1:");	
							asm ("bclr	6,0x00e1");				// SET_VTXD(0); log 1 na linku
    						asm ("mov.b	#PERIOD_10us,r1l");		// loop = PERIOD10us; pockat 10us
    						asm ("mov.b	r1l,r0l");				// loop
    		asm ("WAIT_10us_1:");								// while( loop )
    						asm ("dec.b	r0l");			 		// loop--;
						    asm ("jne	WAIT_10us_1");
//==============================================================================
						    asm ("mov.b	#BITPERIOD_1,r0l");	
			asm ("COLLISION_CHECK:");							// loop = BITPERIOD-PERIOD10us
   							asm ("cmp.b	#0x00,r0l");			// while( loop ) 			
   							asm ("jeq	SHIFT");

						    asm ("dec.b	r0l");					// loop--;
						    asm ("btst	0x07,0x00e1");			// if(!VRXD)
   			 		        asm ("jnz	COLLISION_CHECK");

						    asm ("mov.w	#ERROR_BIT_COLLISION,R0");	// kolize -  return(1);

			    			asm ("bset	2,0x00a5");			// RECEIVER_ENABLE;

    						asm ("fset i");					// enable interrupts
   						    asm ("exitd");					// deallocate stack frame				

//==============================================================================
   																// else - log 0 na linku
   			asm ("SEND_0:");		
							asm ("bset	6,0x00e1");				// SET_VTXD(1);
   							asm ("mov.b	#BITPERIOD_0, r1l");	// loop = BITPERIOD2
   							asm ("mov.b	r1l,r0l");			

   			asm ("LOOP_0:");	
							asm ("dec.b	r0l");					// while( loop ) loop--;
							asm ("nop");
   							asm ("jne	LOOP_0");

//==============================================================================
   			asm ("SHIFT:");		
							asm ("shl.b	#1,r0h");				// cnt <<= 1;
    						asm ("mov.b	r0h,r0l");				// if( cnt ) goto svsenddata;
					   		asm ("jne	SEND_DATA");

//==============================================================================
			asm ("STOP_BIT:");									// log 1 na linku
   							asm ("bclr	6,0x00e1");				// SET_VTXD(0);
   							asm ("mov.b	#PERIOD_10us,r0h");		// loop = PERIOD10us;
   							asm ("mov.b	r0h,r0l");		
			asm ("WAIT_10us_2:");
							asm ("dec.b	r0l");					// loop--
							asm ("jne	WAIT_10us_2");			// while( loop ) 			

//==============================================================================
   							asm ("mov.b	#BITPERIOD_STOP,r0l");	// loop = BITPERIOD1-PERIOD10us
			asm ("COLLISION_CHECK_STOP:");						// while( loop ) 			
   							asm ("mov.b	r0l,r0h");
   							asm ("jeq	SEND_DONE");
		   					asm ("dec.b	r0l");					// loop--;
   							asm ("btst	0x07,0x00e1");			// if(!VRXD)
   							asm ("jnz	COLLISION_CHECK_STOP");
   														// nastala kolize na STOP bitu, nutno pockat >stop_bit time
							asm ("mov.b	#STOP_PERIOD,r0h");		// loop = BYTEMARKER;
   							asm ("mov.b	r0h,r0l");				// loop 
   			asm ("WAIT_STOP_BIT_END:");							// while( loop ) 			
			                asm ("nop");
   							asm ("dec.b	r0l");					// loop--
						    asm ("jne	WAIT_STOP_BIT_END");
   							asm ("mov.w	#ERROR_STOP_BIT_COLLISION,r0");	// kolize - return(2)

			    			asm ("bset	2,0x00a5");				// RECEIVER_ENABLE;

    						asm ("fset i");						// enable interrupts
   					  		asm ("exitd");						// deallocate stack frame

//==============================================================================
// odeslan cely bajt, ale je nutno vlozit kratkou mezeru mezi odesilane bajty
			asm ("SEND_DONE:");
							asm ("mov.w	#SPACE_PERIOD,a0");		// loop = BYTEMARKER;
   			asm ("LOOP_SPACE:");								// while( loop ) 			
   							asm ("dec.w	a0");			 		// loop--;
							asm ("nop");
							asm ("nop");
					   		asm ("jne	LOOP_SPACE");
//==============================================================================
   							asm ("mov.w	#NO_ERROR,r0");		// send ok, return(0);

			    			asm ("bset	2,0x00a5");			// RECEIVER_ENABLE;

    						asm ("fset i");					// enable interrupts
	 					    asm ("exitd");					// deallocate stack frame				
							
}



/******************************************************************************
// EdkBusTimer (void)
// Timer routine for bus accurate timing
// must be called periodically every 1ms
******************************************************************************/
void EdkBusTimer (void)
{
	// pokud nebyl prijat zadny znak po stanovenou dobu nastavi se priznak volne sbernice
	 if (BusControl.Timer_counter) BusControl.Timer_counter--; 
	 if (!BusControl.Timer_counter)
	  {
  	    BusControl.BusState |= BUS_FREE; 
		DataInitPacket();
	  } 

return;
}  // end of BusTimer 




/******************************************************************************
// Init_DigitalThermomoter (void)
//
******************************************************************************/
tUInt Init_DigitalThermometer(void)
{
  tUInt status;

#ifdef USE_ONEWIRE  
  status = DS18B20_Init();
#endif
  
  return (status);
}



/******************************************************************************
// ReadTemperature (void)
// cteni teploty z cisla
******************************************************************************/
void ReadTemperature(void)
{
#ifdef USE_THERMO
  tUInt value;
  tUInt dataType;
  

  // detekce odpojeni - zalohovat aktualni stav
  appCB.sensor.old_presence_state = appCB.sensor.presence_state;			
  	
  // nacteni teploty z cidla	
  value = ds1820_read(); 
  
  // zpracovani navratove hodnoty
  if ((value != 0x1999) && (value != 0xffff))	// osetreni navratove hodnoty v pripade chybneho cteni - 6553d pro odpojene cidlo, tj. 0xffff/10
   {											// 0xffff vraci v pripade chyby cteni
	 EDK.sensor[SENSOR_TEMP].raw = (signed int)value;	// aktualizovat hodnotu do ADC[]
	 appCB.sensor.presence_state = 1;		// indikovat pripojeni cidla za chodu
	 appCB.sensor.presence_counter = 0;		// inicializovat citac 
   }
  else
   {
	 // citac neuspesnych cteni, chybu indikovat jen 1x
	 if (appCB.sensor.presence_counter < PRESET_ONEWIRE_PRESENCE_COUNTER)
	  {
	    appCB.sensor.presence_counter++;
		if (appCB.sensor.presence_counter >= PRESET_ONEWIRE_PRESENCE_COUNTER)
	     {
		   appCB.sensor.first_sample = 1;	// po odpojeni cidla se bude nacitat dallas teplomer
 	       appCB.sensor.presence_state = 0;	// indikovat odpojeni cidla za chodu
	     }
      }
   }

  // pri detekci odpojeni cidla generovat chybovy paket 
  if (!appCB.sensor.presence_state && appCB.sensor.old_presence_state)		// detekovan vstup do poruchy
   {
      AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_MESSAGE_INFO, UNIT_SENSOR_FAIL, 0);
   }
#endif
}



/******************************************************************************
// CheckPowerSupply (void)
// kontrola napajeciho napeti 
******************************************************************************/
void CheckPowerSupply(void)
{
#ifdef USE_VOLT
  tUInt value;
  tUInt dataType;
  

  if (((EDK.sensor[SENSOR_VOLT].data > EDK_PRESET_OPVOLTAGE) && (EDK.sensor[SENSOR_VOLT].data < EDK_PRESET_UNDERVOLTAGE)) && (appCB.sensor.undervoltage==0))	// napeti je mensi nez 10.5V
   {											
     appCB.sensor.undervoltage = 1;

     // pri poklesu napeti pod danou mez generovat paket SYS_MESSAGE_INFO, paket MEASURE az na dotaz 
	 AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_MESSAGE_INFO, UNIT_POWER_LOW, 0);
   }		 
  else if (EDK.sensor[SENSOR_VOLT].data > EDK_PRESET_UNDERVOLTAGE)		// navrat do OK stavu
   {
     appCB.sensor.undervoltage = 0;
   }
#endif   
}



/******************************************************************************
// SendActiveAnalogIoPacket (void)
//
******************************************************************************/
void SendActiveAnalogIoPacket(tUInt packet_type)
{
  tUInt curState;
  
  GUINTADDR	   PT_ADR;
  GUINTRECORD  dataType;
  
  tUInt _total;			// pomocne promene pro nastavovani FIRST/LAST
  tUInt _temp_total;
  
  
  _total = GetActiveAnCount();					// celkovy pocet aktivnich analogovych vstupu
  _temp_total = _total;							// pracovni kopie 
  
  if ( _total != 0)								// pokud je nejaky IO aktivni
   {
									       		// odeslani stavu mereni teploty
  #if defined USE_THERMO		 				// pouze pro variantu teplomeru
	if (appCB.sensor.presence_state)			// posilat paket pouze pokud je pripojene cidlo
	 {
	  dataType.VALUE.LO = SENSOR_TYPE_TEMPERATURE;
	  PT_ADR.X[0] =  SENSOR_CHAN_1;
	  PT_ADR.X[1] = GetFirstLastSign(_total, _temp_total--);		// zjistit jaky nastavit priznak FIRST/LAST
	 
	  if (packet_type == PACKET_MULTICAST)							// v pripade neadresni odpovedi, tj. periodeciskeho generovani stavu
	   {															// nenastavovat priznaky FIRST/LAST
	     PT_ADR.X[1] = 0;
	   }

	  // ve spodnim bajtu se prenasi typ veliciny a v hornim bajtu poradi snimace
	  dataType.VALUE.HI = SENSOR_POS_TEMPERATURE;		// poradi snimace
	  AddReq(PRIORITY_TASK_MID  | ADD_MULTIPLE | PROCESS_SCI_STATE_MEASURE, dataType.X, (tUInt *)&PT_ADR.X);
     }
  #endif


  #if defined USE_VOLT	// melo by byt default u vsech typu
	 // generovat paket MEASURE pro napeti
	 dataType.VALUE.LO = SENSOR_TYPE_VOLTAGE;				
	 PT_ADR.X[0] = SENSOR_CHAN_1;							
	 PT_ADR.X[1] = GetFirstLastSign(_total, _temp_total--);		// zjistit jaky nastavit priznak FIRST/LAST
	 
	 if (packet_type == PACKET_MULTICAST)						// v pripade neadresni odpovedi, tj. periodeciskeho generovani stavu
	  {															// nenastavovat priznaky FIRST/LAST
	    PT_ADR.X[1] = 0;
	  }

	 dataType.VALUE.HI = SENSOR_POS_VOLTAGE;					// poradi snimace
     AddReq(PRIORITY_TASK_MID  | ADD_MULTIPLE | PROCESS_SCI_STATE_MEASURE, dataType.X, (tUInt *)&PT_ADR.X);
  #endif
 }			// konec if ( _total != 0)

}			// KONEC FCE




/******************************************************************************
// SendActiveBinaryIoPacket (void)
//
******************************************************************************/
void SendActiveBinaryIoPacket(void)
{
  tUInt dataType;     
  tUInt curState;
  
  GUINTADDR	  PT_ADR;
  
  tUInt _total;			// pomocne promene pro nastavovani FIRST/LAST
  tUInt _temp_total;

  // poznamka: 
  // princip je takovy, ze se nejdrive zjisti pocet aktivnich IO
  // a nasledne se pred odeslanim zjisti a nastavi priznak FIRST/LAST
  // (mozna zmena vstupu behem tohoto zpracovani se neresi-asi nejde)
	_total = GetActiveIoCount();			// celkovy pocet aktivnich IO
	_temp_total = _total;					// pracovni kopie 
	if ( _total != 0)						// pokud je nejaky IO aktivni
	 {
	   // odeslani stavu RELE
	   if(EDK.output & EDK_OUT_RELAY)
		{
		  curState = 1;								    			// generovat pouze pro aktivni stavy
		  PT_ADR.X[0] = 0x81;										// adresa 1.rele		
		  PT_ADR.X[1] = GetFirstLastSign(_total, _temp_total--);	// zjistit jaky nastavit priznak FIRST/LAST
		  
		  AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_INFO, curState, (tUInt *)&PT_ADR.X);	
		}
									
	   // odeslani stavu vstupu INPUT1	
	   if(EDK.input.state & EDK_IN_INPUT1)							// VSTUP1 je aktivni v pozitivni logice
		{
		  curState = 1;												// generovat pouze pro aktivni stavy
		  PT_ADR.X[0] = 0x01;										// adresa vstupu 1
		  PT_ADR.X[1] = GetFirstLastSign(_total, _temp_total--);	// zjistit jaky nastavit priznak FIRST/LAST
		  
		  AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_INFO, curState, (tUInt *)&PT_ADR.X);											  
		}

										 
		// odeslani stavu vstupu INPUT2	
		if(!(EDK.input.state & EDK_IN_INPUT2))						// VSTUP2 je inverzni
		 {
			curState = 1;											// generovat pouze pro aktivni stavy
			PT_ADR.X[0] = 0x02;										// adresa vstupu 2
			PT_ADR.X[1] = GetFirstLastSign(_total, _temp_total--);	// zjistit jaky nastavit priznak FIRST/LAST
											    
			AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_INFO, curState, (tUInt *)&PT_ADR.X);											  
		 }

		// odeslani stavu vstupu TAMPER
		// pouze pokud je osazen jumper EHS
		if (EDK.input.state & EDK_IN_EHS)
		 {
		   if(EDK.input.state & EDK_IN_TAMPER)
			{
			  curState = 1;												// generovat pouze pro aktivni stavy
			  PT_ADR.X[0] = 0x41;										// adresa tamperu
			  PT_ADR.X[1] = GetFirstLastSign(_total, _temp_total--);	// zjistit jaky nastavit priznak FIRST/LAST
											       
			  AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_INFO, curState, (tUInt *)&PT_ADR.X);											  
			}
		 }		// konec if (EDK.input.state & EDK_IN_EHS)
												
	} 			// konec if ( _total != 0)


}				// konec fce



/******************************************************************************
// rezervovano pro celkovy definovany pocet snesoru a kanalu
/******************************************************************************/
tUChar inputTable[MAX_SENSORS][INPUT_TABLE_RAM_SIZE];
extern const unsigned char sensorTable[MAX_SENSORS][SENSOR_ITEMS];


/**********************************
// getMAX
***********************************/
signed int getMAX(void)
{
  return ( inputTable[appCB.iChk][MAX] << 8 | inputTable[appCB.iChk][MAX_LOW] );
}

/**********************************
// getMIN
***********************************/
signed int getMIN(void)
{
  return ( ( inputTable[appCB.iChk][MIN] << 8 | inputTable[appCB.iChk][MIN_LOW]) );		
}


/************************************
// getLastMIN
// vraci posledni pruchod limitou MIN
// k tomu slouzi nejvyssi bit v MIN
*************************************/
tUInt getLastMIN(void)
{
  return ( inputTable[appCB.iChk][LAST_LIMIT]&LAST_LIMIT_MIN );		
}


/************************************
// getLastMAX
// vraci posledni pruchod limitou MAX
// k tomu slouzi nejvyssi bit v MAX
*************************************/
tUInt getLastMAX(void)
{
  return ( inputTable[appCB.iChk][LAST_LIMIT]&LAST_LIMIT_MAX );		// v nejvyssim bitu je posledni pruchod MIN
}


/************************************
// saveLastMIN
// ulozi posledni pruchod limitou MIN
*************************************/
#define SET_LAST_MIN    inputTable[appCB.iChk][LAST_LIMIT] |= LAST_LIMIT_MIN	// nastavit bit pro MIN
#define CLEAR_LAST_MIN  inputTable[appCB.iChk][LAST_LIMIT] &= ~LAST_LIMIT_MIN	// smazat bit pro MIN

#define SET_LAST_MAX    inputTable[appCB.iChk][LAST_LIMIT] |= LAST_LIMIT_MAX	// nastavit bit pro MAX
#define CLEAR_LAST_MAX  inputTable[appCB.iChk][LAST_LIMIT] &= ~LAST_LIMIT_MAX	// smazat bit pro MAX


/**********************************
// getLAST
// vraci posledni cteni
***********************************/
signed int getLAST(void)
{
  return ( inputTable[appCB.iChk][LAST_STATE] << 8 | inputTable[appCB.iChk][LAST_STATE_LOW] );
}


/**********************************
// saveLAST
// ulozi hodnotu posledniho cteni
***********************************/
void saveLAST(signed int val)
{
  inputTable[appCB.iChk][LAST_STATE] = val>>8;
  inputTable[appCB.iChk][LAST_STATE_LOW] = val;
}


/**********************************
// getCOR
// vraci hodnotu korekce
***********************************/
signed int getCOR(void)
{
  return ( inputTable[appCB.iChk][CORR] );
}


/******************************************************************************
// CHECK_MAX 
// vyhodnoceni prekroceni limity MAX
// podminka resi prekroceni hodnoty smerem nahoru
******************************************************************************/
tUInt CHECK_MAX(signed int  val)
{
  if ((val >= getMAX() ) && (getLAST() < getMAX() ))	
   {

     return 1;				// aby opakovane nevyhodnocovalo pruchod limitou MAX
   }
  
  return 0;
}


/******************************************************************************
// CHECK_MIN 
// vyhodnoceni prekroceni limity MIN
// podminka resi prekroceni hodnoty smerem dolu
// nastavuje se zde pruchod limitou MIN - hystereze
******************************************************************************/
tUInt CHECK_MIN(signed int  val)
{
  if ( val < getMIN() && (getLAST() >= getMIN() ))
     return 1;		// povoli vyhodnoceni limity MAX
  else
     return 0;
}



// zmena vstupu
tUInt CHECK_APAR(signed int  old_value, signed int  new_value)
{
  signed int absvalue;
  
  absvalue = my_abs(new_value-old_value);
  
  if (absvalue > 0)
  return 1;
  
  return 0;						
}


// zmena funkce DELTA 
tUInt CHECK_APAR1(signed int  val)
{
   if ( CHECK_DELTA_UP(val) || CHECK_DELTA_DOWN(val) )
   return 1;
   
   return 0;
}


// zmena funkce analog/digital termostat
tUInt CHECK_APAR2(signed int  val)
{
  if ( inputTable[appCB.iChk][FLAG_IO] & (FCE_ANALOG_THERM|FCE_BINARY_THERM) )
   {
//	 if ( CHECK_MAX(val) || CHECK_MIN(val) )
	  return 1;
   }

   return 0; 
}



signed int  getDELTA(void)
{
  return( inputTable[appCB.iChk][DELTA] );
}




tUInt CHECK_DELTA_UP(signed int  val)
{
  if ( val >= (getLAST() + getDELTA() ))
   return 1;
   
  return 0; 
}



tUInt CHECK_DELTA_DOWN(signed int  val)
{
   if ( val <= (getLAST() - getDELTA() ))
    return 1;

  return 0;	
}


#define CHECK_ATHERM  ( inputTable[appCB.iChk][FLAG_IO] & FCE_ANALOG_THERM)
#define CHECK_BTHERM  ( inputTable[appCB.iChk][FLAG_IO] & FCE_BINARY_THERM)  


/******************************************************************************
// ProcessSensors (void)
// porovna zmerenou teplotu s nastavenymi limity a posle measure paket
******************************************************************************/
void ProcessSensors(void)
{
  tUChar _change = 0;
  signed int inp;
  signed int *input;
  
 
  GUINTRECORD  dataType;
  GUINTADDR  PT_ADR;	
    
	  
  // vzit merenou velicinu, obsah EDK.sensor[] odpovida tabulce sensoru
  // v polozce raw jsou surove data z cidel
  inp = EDK.sensor[appCB.iChk].raw;		

  // nastavit pointer input na polozku kde se ukladaji zde zpracovane hodnoty 
  input = (tUInt*)&EDK.sensor[appCB.iChk].data;	
	   
 
  // -----------------------------------------------------------
  // odstraneni klidove odchylky daneho vstupu - korekce hodnoty 
  // prro teplomery povolujeme zapornou korekci (signed)
  // -----------------------------------------------------------
	if(inp >= getCOR())		
		inp = inp - getCOR();	


  // osetreni pro prvni mereni po spusteni, jekmile obdrzime platnou hodnotu, tak poslat nehlede na stav limit
  // plati pouze pro analogovy termostat
  if(EDK.sys_flag & FLAG_AIO_FIRST_SEND)	// pomocny flag pouze pro tento rezim, analogoveho termostatu
   {										// po zapnuti zajisti odeslani hodnoty
      if (CHECK_ATHERM)				// pro binarni termostat nema vyznam
	    {							// posilat i pro zaporne teploty, ale mame misto toho 0 jako hodnotu
	      _change = 1;
		  *input = inp;				// analogova hodnota
  	      saveLAST(inp);			// ulozit do LAST STATE, protoze odtud to nacita paket 
	    }
      else if (CHECK_BTHERM)		// plati pro binarni termostat a hodnotu pod limitou MIN 
  	   {							// posilat i pro zaporne teploty
	      if (inp < getMIN())
		    {
			  _change = 1;
		      *input = 0;			// binarni stav 0
			}
	   }
   }
		
		
  // -----------------------------------------------------------
  // detekovana zmena vstupu
  // -----------------------------------------------------------
  if(CHECK_APAR(*input, inp) )		
   {
	 //-------------------------------------------------------------------------------
  	 // je to funkce analogovy nebo binarni termostat 
  	 //-------------------------------------------------------------------------------
	 if( CHECK_APAR2(inp) )
	  {													
		//------------------
		// detekce minimum		 
	 	//------------------
		if (CHECK_MIN(inp))
	  	 {
		   // detekovat pruchod limitou pouze 1x
		   if ( getLastMIN()==0 )
		    {
		   	 _change = 1;
		     if ( CHECK_BTHERM ) 
		   		*input = 0;		// binarni stav 0
		   	 else	
		   		*input = inp;	// analogova hodnota
		    }
		   SET_LAST_MIN;
		   CLEAR_LAST_MAX; 
	     }

		//------------------
	 	// detekovat maxima
		//------------------	 	
	 	if (CHECK_MAX(inp))
	  	 {
	       // minimum detekovat pri vstupu pouze 1x
		   if ( getLastMAX() == 0)
		    {
		      _change = 1;
			
		   	  if ( CHECK_BTHERM ) 
		    	  *input = 1;		// binarni stav 1
		   	  else	
		    	  *input = inp;	// analogova hodnota
		  	}
			SET_LAST_MAX;
			CLEAR_LAST_MIN; 
	  	 }


	 // -----------------------------------------------------------	
     // ulozit stav pro pristi kontrolu, pro funkci delta to neplati
     // nutno doresit ukladani obou kanalu do laststate
     if( !(inputTable[appCB.iChk][FLAG_IO] & FCE_DELTA))	
      {
	    saveLAST(inp);				   		 						
      }
  
  }					// konec APAR2
  
  	
	//-------------------------------------------------------------------------------
  	// normalni funkce DELTA
	//-------------------------------------------------------------------------------		   
     else if(inputTable[appCB.iChk][FLAG_IO] & FCE_DELTA)								
      {
		if ( CHECK_APAR1(inp) )
	     {
		   saveLAST(inp);
		   *input = inp;
		   _change = 1;		// vyhodnocni zmeny musi byt az zde
	     }
      }
    
  }					// konec  if(CHECK_APAR(*input, inp) )	



  // -----------------------------------------------------------	
  // vyhodnoceni zmeny
  // -----------------------------------------------------------	
  if( _change )   
   {													
	 dataType.VALUE.HI = sensorTable[appCB.iChk][SENSOR_POSITION];	// poradi sensoru podle tabulky sensoru
	 dataType.VALUE.LO = sensorTable[appCB.iChk][SENSOR_TYPE];		// typ merne veliciny

	 PT_ADR.X[0] =  sensorTable[appCB.iChk][SENSOR_CHANNEL];			// informace o kanalu
	 PT_ADR.X[1] = 0;													// priznak first/last nenastavovat

     // nutno rozlisit jaky paket poslat, pokud jde o funkci binarni termostat posila se STATE_CHANGE
	 // pro analogovy termostat se posila take STATE_MEASURE
	 if ( inputTable[appCB.iChk][FLAG_IO] & FCE_BINARY_THERM )
	  {
		PT_ADR.VALUE_X.X0_HI = sensorTable[appCB.iChk][SENSOR_POSITION];
	    PT_ADR.VALUE_X.X0_LO = sensorTable[appCB.iChk][SENSOR_CHANNEL];
		PT_ADR.X[1] = 0;													// priznak first/last nenastavovat
		AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_STATE_CHANGE, *input, (tUInt *)&PT_ADR.X);
	  }
	 else
	  {
	    AddReq(PRIORITY_TASK_MID  | ADD_MULTIPLE | PROCESS_SCI_STATE_MEASURE, SWAP(dataType.X), (tUInt *)&PT_ADR.X);		
	  }	 

   } // konec change



  //-----------------------------------------------------------------------------
  // prochazet tabulku sensoru, v prvnim poli je poradi sensoru v ramci zarizeni
  //-----------------------------------------------------------------------------
  if(sensorTable[appCB.iChk][0] == NULL)	    // konec tabulky sensoru
   {
	 appCB.iChk = 0;							// konec seznamu
 	 EDK.sys_flag &= ~FLAG_AIO_FIRST_SEND;	    // zhodit flag
   }
  else
   {
	 appCB.iChk++;		// vzit dalsi sensor
   }

}			// konec fce


