/*****************************************************************************************************************
*	S C I .c
*
* 
*
*
*****************************************************************************************************************/
#include "includes.h"
#include "timers.h"

extern unsigned int	_gUnitAddr;			// store the bus ID address
extern tsTitle		cfgstitle;			// prostor v RAM pro strukturu TITLE 
extern tsConstant 	cfgsystem; 			// prostor v RAM pro strukturu CONSTANT 

#define	SCR3_DEF_STATE	0x80
#define	makeODD(mv)		mv = ((mv+1)&0xfe)				// upravi vlozenou hodnotu na sude cislo

tUChar gDataType[MAX_MESSAGE_LEN-SYS_HEADER_LEN-2];		// uchovava datovy obsah pro zpracovani DLL, RDI
tUChar gDataHeader[SYS_HEADER_LEN+2];					// uchovava datovy obsah hlavicky a nasledujici
														// 2 bajty s adresou odesilatele



/*************************************************************************
*Name:  pushRxHeader
*Description: 
*************************************************************************/
void pushRxHeader(tUChar *_p, tUInt _l )
{
   my_memcpy( &gDataHeader[0], _p, _l);					// prekopirovat data do bufferu
}



/*************************************************************************
*Name:  pushSCIData
*Description: 
*************************************************************************/
void pushSCIData(tUChar *_p, tUInt _l )
{
   BusControl.BusState |= SCI_BUSY;
   
   my_memcpy( &gDataType[0], _p, _l);					// prekopirovat data do bufferu
}



/*************************************************************************
*Name:  popSCIData
*Description: 
*************************************************************************/
void popSCIData( void )
{
   my_memset(&gDataType[0], 0, sizeof(gDataType));
   BusControl.BusState &= ~(SCI_BUSY);
}


/*************************************************************************
*Name:  packetRepeatError
*Description: 
*************************************************************************/
void packetRepeatError()
{							
	appCB.StatValue[0]++;
	appCB.error = ERR_SCI_SEND;
}



//+-------------------------------------------------------------------+
//| SCI_GetPacketType()
//| return type of received packet
//+-------------------------------------------------------------------+
unsigned int  SCI_GetPacketType(void)
{
  #ifdef INTERFACE_RS					// funkce je platna jen pro EDK+RS s rozhranim RS
    return( SWAP(gPh->ph_PID.INT));
  #endif	
}	


//+-------------------------------------------------------------------+
// InfoSciMessage()
// odeslani systemove zpravy SYS_MESSAGE_INFO - IO_ADR=0
//+-------------------------------------------------------------------+
void InfoSciMessage(void)
{
 
  //DataCreateSystemMessage(SYS_MESSAGE_INFO, reqBuffer[appCB.task].addr[0], reqBuffer[appCB.task].parameter); 
  DataCreateSystemMessage(SYS_MESSAGE_INFO, 0, reqBuffer[appCB.task].parameter); 

  SendPacket(SYS_MESSAGE_LEN);
	
  return;	
}



//+-------------------------------------------------------------------+
//| AckSciMessage() - vola se z fronty uloh
//| odeslani systemove zpravy - paket ACK s Error code
//+-------------------------------------------------------------------+
void AckSciMessage (void)
{
#ifdef INTERFACE_RS					
  //DataCreateMessageHeader( (reqBuffer[appCB.task].parameter&0xFF00)|PAC_TYPE_ACK, reqBuffer[appCB.task].addr[1], reqBuffer[appCB.task].addr[0], (reqBuffer[appCB.task].parameter));  // posilat RID
  DataCreateMessageHeader( (reqBuffer[appCB.task].parameter&0xFF00)|PAC_TYPE_ACK, reqBuffer[appCB.task].addr[1], reqBuffer[appCB.task].addr[0], (reqBuffer[appCB.task].parameter & 0x00ff));  // neposilat RID v ACk paketu, jenom v Error paketu
  SendPacket(SYS_HEADER_LEN);
#endif

return;	
}



//+-------------------------------------------------------------------+
//| sendAckPacket()
//| 
//+-------------------------------------------------------------------+
void sendAckPacket(char _ack_state)
{							
  tUInt temp;
  
  gDataHeader[1] = _ack_state;							// stavovy kod

 // prohodit endian v cele hlavicce
 for (temp=0; temp<(SYS_HEADER_LEN+2)*2; temp+=2)		// offset je integer
  {
    *(tUInt*)&gDataHeader[temp] = SWAP (*(tUInt*)&gDataHeader[temp]);		
  }
 
 
  // zadani pozadavku na vytvoreni a odeslani ACK paketu
  // parametr = PID+gData.SciState
  // addr = RID + adresa odesilatele
  AddReq(PRIORITY_ACK_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_ACK, *((tUInt *)gDataHeader), (tUInt*)&gDataHeader[SYS_HEADER_LEN-2]);
}




//+-------------------------------------------------------------------+
//| ErrorSciMessage()
//| odeslani systemove zpravy SYS_MESSAGE_ERROR
//+-------------------------------------------------------------------+
void ErrorSciMessage(void)
{
  DataCreateSystemMessage(SYS_MESSAGE_ERROR, reqBuffer[appCB.task].addr[0], reqBuffer[appCB.task].parameter); 

  SendPacket(SYS_MESSAGE_LEN);
  	
  return;	
}


//+-------------------------------------------------------------------+
//| ChangeSciMessage()
//| odeslani systemove zpravy SYS_STATE_CHANGE
//+-------------------------------------------------------------------+
void ChangeSciMessage(void)
{
  DataCreateSystemMessage(SYS_STATE_CHANGE, reqBuffer[appCB.task].addr[0], reqBuffer[appCB.task].parameter); 

  SendPacket(SYS_MESSAGE_LEN);
  
  return;	
}


//+-------------------------------------------------------------------+
//| StateSciMessage()
//| odeslani systemove zpravy SYS_STATE_INFO
//+-------------------------------------------------------------------+
void StateSciMessage(void)
{
  // zmena oproti puvodnimu protokolu - v addr[1] je nutne prenaset priznak FIRST/LAST
  DataCreateSystemMessage(SYS_STATE_INFO|(reqBuffer[appCB.task].addr[1]&0x00ff), reqBuffer[appCB.task].addr[0], reqBuffer[appCB.task].parameter); 

  SendPacket(SYS_MESSAGE_LEN);
  
  return;	
}


//+-------------------------------------------------------------------+
//| ReaderSciMessage()
//| odeslani systemove zpravy SYS_STATE_READER
//+-------------------------------------------------------------------+
#ifdef CORE_EDK
void ReaderSciMessage(void)
{
#ifdef INTERFACE_RS				// a rozhrani RS

	tUChar msgLen, io_len;
	tUInt pstv;
	unsigned int _ep;
    
	GUINTRECORD   PT_ADR;	

    DataCreateMessageHeader(SYS_STATE_READER, 0, 0, 14);  		// UNICAST paket 

//-----------------------------
// datova cast
//-----------------------------
	msgLen=0;
// adresa odesilatele
	gData.bufferTxD[SYS_HEADER_LEN+1] = (_gUnitAddr & 0x00FF);
	gData.bufferTxD[SYS_HEADER_LEN] = (_gUnitAddr>>8);
	msgLen+=2;

// ADR_MODUL
	gData.bufferTxD[SYS_HEADER_LEN+2] = 0x00;
// adresa ctecky v ramci jednotky (ADDR_IO)
	gData.bufferTxD[SYS_HEADER_LEN+3] = 0x01;
	msgLen+=2;
	

// platny kod karty
	gData.bufferTxD[SYS_HEADER_LEN+4] = 0x01;
// IO STATE - karta priblizena/oddalena 
	gData.bufferTxD[SYS_HEADER_LEN+5] = reqBuffer[appCB.task].parameter;	// parametr funkce ze cteni karty
	msgLen+=2;

 
	// cislo karty - pro EMMARIN se uklada vsech 5 bajtu, odesila se standartne 4 bajty {bez prvniho MFCode)
	// v propade MIFARE, jsou 4 bajty ulozeny od cardId[1] 
  #ifdef READER_EMMARIN
	gData.bufferTxD[SYS_HEADER_LEN+6]  = gCard.cardId[1];	// 2.bajt
	gData.bufferTxD[SYS_HEADER_LEN+7]  = gCard.cardId[2];	// 3.bajt
	gData.bufferTxD[SYS_HEADER_LEN+8]  = gCard.cardId[3];	// 4.bajt
	gData.bufferTxD[SYS_HEADER_LEN+9]  = gCard.cardId[4];   // 5.bajt
  #endif
  
  // MIFARE posilame cislo karty odkonce, aby to bylo stejne jako R10
  #ifdef READER_MIFARE
	gData.bufferTxD[SYS_HEADER_LEN+6]  = gCard.cardId[4];	// 4.bajt
	gData.bufferTxD[SYS_HEADER_LEN+7]  = gCard.cardId[3];	// 3.bajt
	gData.bufferTxD[SYS_HEADER_LEN+8]  = gCard.cardId[2];	// 2.bajt
	gData.bufferTxD[SYS_HEADER_LEN+9]  = gCard.cardId[1];   // 1.bajt
  #endif
	msgLen+=4;

// PIN
	gData.bufferTxD[SYS_HEADER_LEN+10] = 0x00;  
	gData.bufferTxD[SYS_HEADER_LEN+11] = 0x00;
	msgLen+=2;

	DataAddCrcMessage( 12 ); 
	msgLen+=2;

    SendPacket(SYS_HEADER_LEN + msgLen);
  
    // po odeslani smazat zdrojovy buffer s cislem karty
	//my_memset(&gCard.cardId[0], 0, sizeof (gCard.cardId) );
	
//	gCard.cardId[1];

  
    return;	

#endif
}
#endif


//+-------------------------------------------------------------------+
//| ParseSciRxData()
//| zpracovani dat z vyrovnavaciho bufferu gRx
//| dekoduji se jednotlive pakety a rozhoduje co dal
//+-------------------------------------------------------------------+
void ParseSciRxData(void)
{
#ifdef INTERFACE_RS								// funkce je platna jen pro EDK+RS s rozhranim RS

  int	rpState;
  unsigned char recvLen;
  
  tUInt dataType;     
  tUInt curState;
  
  GUINTADDR	  PT_ADR;
  
  tUInt _total;			// pomocne promene pro nastavovani FIRST/LAST
  tUInt _temp_total;

  recvLen=0;
     
   if (!(BusControl.BusState & BUS_FREE))		// parsuje se jen pokud je volna sbernice
    {
		return;
	}													

   if(!gRxPos) { return; }						// neni nic ke zpracovani
    {
        RX_InterruptDisable;					// po dobu zpracovani kruhoveho bufferu zakazat SCI preruseni

		// zpracovani kazdeho prijateho byte - paket se postupne uklada se do gData.bufferRxD kde jsou k disposici pro dalsi zpracovani
		// pokud vrati hodnotu > 0 je prijat cely paket a budou se zpracovavat data
		rpState = SCI_RecvPacket( gRx[gRxOfs], &recvLen );

	      if (gRxPos)
		   {
			 gRxPos --;
      	     gRxOfs ++;
	         gRxOfs &= RX_BUFF_SIZE;			// bufer je kruhovy
		   }
	    RX_InterruptEnable;
		
	
	    // chyba v paketu, nebo byl dlouhy
	    // generovat ACK paket se statusem chyby ktera byla vracena v gData.SciState z funkce SCI_RecvPacket
		if( rpState < 0)
		 {
		   // do spodni casti PID ulozit status odpovedi
		   gData.bufferRxD[1] = gData.SciState&0x0f;
			
		   // paket je adresovany vyhradne pro nas
		   if( rpState == PACKET_SINGLECAST )		
	    	{
			  // zadani pozadavku na vytvoreni a odeslani ACK paketu    parametr = PID+gData.SciState			    addr = RID + adresa odesilatele
			  sendAckPacket(ERR_SUCCESS);
			}
		   
		   // inicializace promennych pro dalsi paket	
		   DataInitParse();
		 }


	    // paket je prijat korektne - probehne obsluha paketu
		// hodnota rpState urcuje kam byl paket adresovan (unicast, nam primo, broadcast) 
		if( rpState > 0)
		 {
		   // pro snadnejsi ACKobvani zaveden buffer pro ulozeni hlavicky paketu
		   pushRxHeader(gData.bufferRxD, SYS_HEADER_LEN+2);		// zalohovat celou hlavicku + adresu odesilatele
									   
		  // *************************************************************************	
		  // musi se vyfiltrovat nedatove pakety (ACK, ERR) a pouze ty primo pro nas
		  // ACK paket se dale zpracuje podle RID a pokud je negativni provede se znovu odeslani puvodnich dat				 
			if( SCI_PACKETTYPE == PAC_TYPE_ACK )	
			 {
			   if( rpState == PACKET_SINGLECAST )	// paket urcen vyhradne pro nas
			    {
				  // zatim se musi zahodit a dale s nim nepracovat
				  //!!DODELAT			
				  // zde kontrolovat prijaty ACK
				  // mozna sloucit ze vsech projektu a umistit spolecne do commonfiles
			    }					 
				
	   		   // inicializace promennych pro dalsi paket	
		   	   DataInitParse();
		   	   return;
			 }

		  // *************************************************************************
		  // ERR zatim ignorujem vsechny
			if( SCI_PACKETTYPE == PAC_TYPE_ERR )	
			 {
			   //...
	   		   // inicializace promennych pro dalsi paket	
		   	   DataInitParse();
		   	   return;
			 }
			
		   	// signalizace celeho datoveho paketu urceneho pro nas - na zlute led
		   	#if !defined CORE_EDK && !defined CORE_POW
				LED_YELLOW_ON(); 
		   	#endif


				    // cely paket se dale zpracuje podle jeho hlavicky
					rpState = SCI_PACKETPID;
					switch(SCI_PACKETPID)
					 {
						//*********************************************			
						case SYS_MESSAGE_ERROR:	   
							// berem na vedomi, ale zadna odpoved
						  break;

						//*********************************************
						case SYS_STATE_READER:	   
							// berem na vedomi, ale zadna odpoved
						  break;

						//*********************************************
						case SYS_MESSAGE_TIME:	   
							// berem na vedomi, ale zadna odpoved
						  break;

						//*********************************************
						case SYS_STATE_MEASURE:
						  	// bereme na vedomi, ale neodpovidat
						  break;
					  
						
						//*********************************************
						// periodicke dotazovani z ridici jednotky
						case SYS_MESSAGE_INFO:	   

	   						// pokud nastaviny bity pro zapis
							if( SWAP(gPh->ph_PID.INT)&PAC_FLAG_WRITE )	
							 {
 							   pushSCIData((gData.bufferRxD+SYS_HEADER_LEN+2), 2);	// vzit parametr UNIT_STATE
							   if (SWAP(*(tUInt*)&gDataType[0]) == UNIT_NORMAL)		// stavovy kod-dotazovaci paket z master-offline rezim
							    {
								  EDK.sys_flag &= ~FLAG_OFFLINE_MODE;	// zrusit OFFLINE rezim
								  EDK.counter.comm_timeout = 0;			// inicializovat citac
								 
				  			      // omezeni pro variantu POW
								  #if defined CORE_EDK
								    SetDefaultLedState();			     									
				  			      #endif
								}
				   		     }
						 break;										
			  	  
				  
	   					//*********************************************
						case SYS_STATE_CHANGE:	   
							// berem na vedomi, ale zadna odpoved
					 	  break;


						//*********************************************							
						case SYS_DATA_STV:	   
							
							// nastavit datovy klid na sbernici, na dobu nezbytne nutnou, aby se neposilaly pakety MEASURE apod...
							EDK.sys_flag |= FLAG_PROCESS_STV_CMD;		// nastavit blokujici flag
							appCB.cycles1sec = 0;						// inicializovat citac
							
							// ulozit co se pozaduje adresovat					
							appCB.SciTmp = SWAP(*(unsigned int *)(gData.bufferRxD+SYS_HEADER_LEN+2));		// zde je REQUEST
							appCB.SubMenu_tmp.X = SWAP(*((tUInt *)(gData.bufferRxD+SYS_HEADER_LEN+4)));		// zde je WRITE

							// pro zapis se data prenaseji pres globalni buffer, abysme nebyli omezeni delkou v budoucnu
							if( SWAP(gPh->ph_PID.INT)&PAC_FLAG_WRITE )
							 {
							  // ulozit data pro zpracovani
							  // soucasne se nastavi priznak BUSY	nez bude zpracovano aby se neprepsaly jinym prikazem
							   pushSCIData((gData.bufferRxD+SYS_HEADER_LEN+4), SWAP(gPh->ph_datalen)-4); 	// vzit 10 bajtu
							 }
								
							switch (appCB.SciTmp)		// podle parametru REQUEST generovat odpoved
							 {
							   //---------------------------------------------------------------------
							   // zakladni data
							   case 0x00:				
							   	   // predat i puvodni paket kvuli RID a take predat MAC odesilatele
								   AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_STATE_STV, *((tUInt *)(gData.bufferRxD)), &gData.bufferRxD[SYS_HEADER_LEN-2]);
							    break;
								   
							   //---------------------------------------------------------------------
							   // rozsirena data
							   case 0x01:				
							   	   // predat i puvodni paket kvuli RID a take predat MAC odesilatele
								   AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_STATE_STV, *((tUInt *)(gData.bufferRxD)), &gData.bufferRxD[SYS_HEADER_LEN-2]);
							    break;

							   //---------------------------------------------------------------------
							   // nazev jednotky
							   case 0x02:				
							   	   // zapis nazvu jednotky - nenei doreseno rezim read/modify/write do dataflash
								   if( SWAP(gPh->ph_PID.INT)&PAC_FLAG_WRITE )
								    {
  									  if ( Write_RomTitle(&gDataType[0]) == NO_ERROR)
									    sendAckPacket(ERR_SUCCESS);
									  else
									  	sendAckPacket(ERR_EEPROM_WRITE);
									}
								   // cteni nazvu jednotky
								   else		
								    {	
									  // predat i puvodni paket kvuli RID a take predat MAC odesilatele
									  AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_STATE_STV, *((tUInt *)(&cfgstitle.string)), &gData.bufferRxD[SYS_HEADER_LEN-2]);
									}
								 break;

							   
							   //---------------------------------------------------------------------		
							   // globalni data
							   case 0x10:				
							   	   // zapis
								   if( SWAP(gPh->ph_PID.INT)&PAC_FLAG_WRITE )	
								    {
							  		  // ulozit data pro zpracovani
							   		  pushSCIData((gData.bufferRxD+SYS_HEADER_LEN+9), 2);	// vzit jen parametr CONFIG1-HIGH a LOOPINP

									  if (gDataType[0] & 0x80)					// CONFIG1_HIGH = konfigurace pro EDK
									   {
										 EDK.config.check_offline = 1;			// povoleno hlidat spojeni s terminalem
										 SetDefaultLedState();					// pokud je jiz aktivovana jina indikace, zmenit stav LED na default
										 EDK.sys_flag &= ~FLAG_OFFLINE_MODE;	// inicializovat jako ze offline neni
										 EDK.counter.comm_timeout = 0;			// a inicializovat TIMEOUT citac
									   }
									  else 
									   {
										 EDK.config.check_offline = 0;			// zrusit rezim hlidani komunikace s terminalem
 										 EDK.sys_flag &= ~FLAG_OFFLINE_MODE;	// zrusit OFFLINE mod pokud byl aktivovan
										 SetDefaultLedState();					// pokud je jiz aktivovana jina indikace, zmenit stav LED na default
									   }
										
									   // LOOPINP - interval v sekundach
									   EDK.config.loopinp = gDataType[1];		
									   
									   if ( WriteConfig() == NO_ERROR)
									     sendAckPacket(ERR_SUCCESS);
									   else
									     sendAckPacket(ERR_EEPROM_WRITE);
							   	    }
								   // cteni
								   else											
								    {	
								      AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_STATE_STV, *((tUInt *)(gData.bufferRxD)), &gData.bufferRxD[SYS_HEADER_LEN-2]);
									}
								 break;

								 								   
								//---------------------------------------------------------------------								   
								// rezim komunikace
								case 0x1d:									
								  if (appCB.SubMenu_tmp.X == 0x0000) 
								   {
									 sendAckPacket(ERR_SUCCESS); // test
									 BusControl.BusState &= ~BUS_QUIET;		// normalni rezim
									 RestoreIdleLedState();
									 
								   }													
								  else if (appCB.SubMenu_tmp.X == 0x00ff)	
								   {
									 sendAckPacket(ERR_SUCCESS); // test
									 EDK.sys_flag |= FLAG_ACK_BUS_QUIET;	// pomocny flag, po odeslani ACK paketu	se teprve nastavi BUS_QUIET
									 SetQuiteLedState();
								   }
								 break;


								//---------------------------------------------------------------------
								// rizeni jednotky
								case 0x1E:									
		  						
								  // zapis
								  if( !(SWAP(gPh->ph_PID.INT)&PAC_FLAG_WRITE ))	
								   {
								     sendAckPacket(ERR_SCI_WRONLY);				// pokud neni nastaven bit WRITE, hlasit chybu
							   	   }
							      else
								   {  
								    // normalni reset
									if (appCB.SubMenu_tmp.X == 0x0000) 			
								     {
									   sendAckPacket(ERR_SUCCESS); 						// nejdrive Ackovat a pak provest restart
									   AddReq(PRIORITY_TASK_LOW | DEVICE_RESET, 0,0);	// bude trvat 10s nez se odesle
								     }													
								    
									// aktivace bootloaderu
									else if (appCB.SubMenu_tmp.X == 0x00FF)		
								     {											
								       appCB.mode |= UNIT_BOOT_MODE;
									   //AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_MESSAGE_INFO, UNIT_BOOT_DLL, 0);
									   	sendAckPacket(ERR_SUCCESS); // test
								     }
								    
									// deaktivace do bootloaderu
									else if (appCB.SubMenu_tmp.X == 0xFF00)		
								     {
								       appCB.mode &= ~UNIT_BOOT_MODE;
									   //AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_MESSAGE_INFO, UNIT_NORMAL, 0);
									   sendAckPacket(ERR_SUCCESS); // test
								     }

									// restart do bootloaderu - smaze cely prostor FLASH
								    else if (appCB.SubMenu_tmp.X == 0xFFFF)		
								     {										
									 //jeste radeji neuvolnovat  RestartToBootloader();					// nastavi prechod do bootloaderu, ktery nasledne po 
									 											// resetu smaze cely prostor FLASH pro aplikaci
								     }
									
									// debug rezim
								    else if (appCB.SubMenu_tmp.X == 0x0010)		
								     {
								       sendAckPacket(ERR_SCI_BADVALUE); 		// nepodporovana hodnota
								     }
								    
									// obnova default konfigurace
									else if (appCB.SubMenu_tmp.X == 0xAA00)		
								     {
								    	if ( InitConfig() == NO_ERROR )
										 {
										   InitAPP();							// inicializace MAC apod...
										   Read_InputConfig();					// znovunacteni config limity apod...
										   sendAckPacket(UNIT_LOAD_DEF); 		// provedeno OK
										 }
								   	    else
										 {	
									 	   sendAckPacket(ERR_EEPROM_WRITE);
										 }
									 }
									}	// ZAPIS
								 break;


								//---------------------------------------------------------------------
								// odeslání stavu zařízení (w) zařízení odpoví SYS_MESSAGE_INFO 
								case 0x20:					
								   
								   // nejprve vyhodnoceni chybovych stavu zarizeni
								   if (!appCB.sensor.presence_state)		// odpojene cidlo?
								    {
								      AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_MESSAGE_INFO, UNIT_SENSOR_FAIL, 0);
									}
								   else if (appCB.sensor.undervoltage)			// chyba podpeti?
								    {
								      AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_MESSAGE_INFO, UNIT_POWER_LOW, 0);
									}
								   else 									// vse OK?
									{
									  // podle rezimu, hlasit stav zarizeni, bud normalni rezim, nebo boot
			  						  if (appCB.mode & UNIT_BOOT_MODE)
			   						   {
									     AddReq(PRIORITY_TASK_MID | PROCESS_SCI_MESSAGE_INFO, UNIT_BOOT_DLL, 0);
			   						   }
									  else
									   {
									     AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_MESSAGE_INFO, UNIT_NORMAL, 0);
									   }
									}
											   										
								   break;

			   
								//---------------------------------------------------------------------
								// odeslání aktivních stavů (w) nastavení požadavku na hromadné  
           						// zjistění stavů IO, zařízení odpoví skupinu paketů SYS_STATE_INFO 
           						// pro aktuálně sepnuté IO
								case 0x21:				
		   						  // pro tento prikaz musi byt nastaven WRITE bit, a predan parametr v datovem poli WRITE
								  if( SWAP(gPh->ph_PID.INT)&PAC_FLAG_WRITE )		// kontrola WRITE bitu
								   {		   
								     if (SWAP(gPh->ph_datalen) < 8)					// v paketu chybi datove pole WRITE
									  {
										sendAckPacket(ERR_SCI_EVEN);
									    break;
									  }
								  
									 appCB.SciTmp =  SWAP(*(tUInt*)&gDataType[0]);	// prevzit pole WRITE
										
									 // ------------------------------------------------------	
									 if ( appCB.SciTmp > 3)							// osetreni povoleneho rozsahu v poli WRITE
									  {
										sendAckPacket(ERR_SCI_RANGE);				// data mimo rozsah
										break;										// ukoncit parsovani
									  }

									 // nejdrive ackovat prijem paketu 
									 sendAckPacket(ERROR_CODE_NONE);											
											   														
									 // ------------------------------------------------------	
									 // WRITE=0x00 nebo 0x0001 odesila pouze binarni IO								  
									 if ((appCB.SciTmp == 0x0000) || (appCB.SciTmp & 0x0001))		
									  {
										SendActiveBinaryIoPacket();
									  }
									  // ------------------------------------------------------	
									  // WRITE = 0x0002 - odesila analogove IO									 
									  if (appCB.SciTmp & 0x0002)						// tento stav se nevylucuje s predchazejicim!
									   {
									     SendActiveAnalogIoPacket(PACKET_SINGLECAST);	// odpoved na zadost konkretni jednotky
									   }	
								   break;


								// pro instrukce ktere nejsou vyse definovany hlasit nepodporovana instrukce
								   default:
								       sendAckPacket(ERR_SCI_BADVALUE);					// nepodporovana instrukce
									break;

								 }				// konec if( SWAP(gPh->ph_PID.INT)&PAC_FLAG_WRITE )
							  else				
							   {
								 sendAckPacket(ERR_SCI_WRONLY);		// pokud neni nastaven bit WRITE, hlasit chybu
							   }
								  
							}   // KONEC if( SWAP(gPh->ph_PID.INT)&PAC_FLAG_WRITE )
							
						break;


						//*********************************************							
						case SYS_DATA_CFG:	   
							// ulozit co se pozaduje adresovat					
							appCB.SciTmp = SWAP(*(unsigned int *)(gData.bufferRxD+SYS_HEADER_LEN+2));		// REQUEST

							if( (SWAP(gPh->ph_PID.INT)&PAC_FLAG_WRITE) )	// pustit pouze cteni
								sendAckPacket(ERR_SCI_READONLY);
							else if(appCB.SciTmp > 1)						// generovat chybovy paket pokud je mimo rozsah	
							  sendAckPacket(ERR_SCI_RANGE);
							else 
							   // pozadavek na obslouzeni prichozi udalosti dotaz 					parametr = PID				  addr = RID + adresa odesilatele
						       AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_DATA_CFG, *((tUInt *)(gData.bufferRxD)), (tUInt*)&gData.bufferRxD[SYS_HEADER_LEN-2]);							
						 break;


						//*********************************************
						case SYS_DATA_DLL:	   

							// pozadavek na prechod do download rezimu - bootloader
							//appCB.SciTmp = (tUChar)SWAP(*((tUInt *)(gData.bufferRxD+SYS_HEADER_LEN+2)));	
							appCB.SciTmp = gData.bufferRxD[SYS_HEADER_LEN+2];	

							switch (appCB.SciTmp)
				 	 		 {
				   	   		 	// 0x10 - zapis MAC adresy
				   	   			case DLL_MAC_DATA:										
							     // ukladat jen kdyz je volny buffer
							     if (!(BusControl.BusState & SCI_BUSY))					
							 	  {																
							   	    pushSCIData(&gData.bufferRxD[SYS_HEADER_LEN+2], gData.bufferRxD[SYS_HEADER_LEN+2+1]);		// zkopirovat delka dat z paketu +2 bajty ID+LEN
							   	    AddReq(PRIORITY_SYS_MESSAGE | PROCESS_SCI_DLL_DATA, *((tUInt *)(gData.bufferRxD)), &gData.bufferRxD[SYS_HEADER_LEN-2]);
							 	  }						
							     break;


				   	   			// 0x11 - zapis dat pro upload FW
				   	   			case DLL_FW_DATA:			
									// ulozit data pro zpracovani
									// soucasne se nastavi priznak BUSY	nez bude zpracovano aby se neprepsaly jinym prikazem
									// uklada se cely obsah datove zpravy tj. ID+LEN+DATA
									if (!(BusControl.BusState & SCI_BUSY))					// ukladat jen kdyz je volny buffer
						 	 		 {																
						   	   		   pushSCIData( &gData.bufferRxD[SYS_HEADER_LEN+2], gData.bufferRxD[SYS_HEADER_LEN+3]+2);		
						   	   		   AddReq(PRIORITY_SYS_MESSAGE | PROCESS_SCI_DLL_DATA, *((tUInt *)(gData.bufferRxD)), &gData.bufferRxD[SYS_HEADER_LEN-2]);
						 	 		 }						
					   			 break;
	
	
					   			// 0x20 - zapis emergency karet
				   	   			// 0x21 - vymazani dane pozice 
					   			case DLL_ECR_DATA:			
					   			case DLL_ECR_REMOVE:	
 						 			#ifdef CORE_EDK
									 if (!(BusControl.BusState & SCI_BUSY))					// ukladat jen kdyz je volny buffer
							 		  {																
							   			pushSCIData( &gData.bufferRxD[SYS_HEADER_LEN+2], gData.bufferRxD[SYS_HEADER_LEN+3]+2);	// zkopirovat delka dat z paketu +2 bajty ID+LEN		
							   			AddReq(PRIORITY_SYS_MESSAGE | PROCESS_SCI_DLL_DATA, *((tUInt *)(gData.bufferRxD)), &gData.bufferRxD[SYS_HEADER_LEN-2]);
							 		  }						
					     		    #endif
					   			 break;
								
								// 0x0B - prednastaveni vstupu/vystupu 
					   			case DLL_IO_PRESET:			
		     					 // ukladat jen kdyz je volny buffer
							     if (!(BusControl.BusState & SCI_BUSY))					
							 	  {																
							   	    pushSCIData(&gData.bufferRxD[SYS_HEADER_LEN+2], gData.bufferRxD[SYS_HEADER_LEN+3]);		
							   	    AddReq(PRIORITY_SYS_MESSAGE | PROCESS_SCI_DLL_DATA, *((tUInt *)(gData.bufferRxD)), &gData.bufferRxD[SYS_HEADER_LEN-2]);
							 	  }	
								 break;


								// VSE OSTATNI HLASI CHYBU DATA MIMO ROZSAH
								default:
								  sendAckPacket(ERR_SCI_RANGE);				// data mimo rozsah
								 break;
	

			 			}		// konec switch (appCB.SciTmp)

						break;		// konec case SYS_DATA_DLL


	
						/*******************************************************************/		
						// verze SYS_DATA_CTRL ktera ovlada jen RELE
						// ledky jsou ovladany prikazem GUI						
						/*******************************************************************/		
						case SYS_DATA_CTRL:	   
						
							// toto doresit
							// ackovat prijeti paketu, provest hned na zacatku, nez se zacne do fronty davat neco jineho
							//	sendAckPacket(ERR_SUCCESS);

								appCB.SciTmp = *(unsigned char *)(gData.bufferRxD+SYS_HEADER_LEN+6);		// hodnota VALUE
							    appCB.SubMenu_tmp.X = *((tUChar *)(gData.bufferRxD+SYS_HEADER_LEN+7));		// funkce FN_HWX
								
								switch (appCB.SubMenu_tmp.X)
								 {
									// pouze prime ovladani rele, ne pres funkci FN_HWX
									case HWX_NO_EVENT:														
										if (appCB.SciTmp == 0x01)
										 {
 										   #ifdef CORE_EDK
											PT_ADR.X[0] = 0x81;				// adresa 1.rele
			 								curState = 0x01;				// stav rele zapnuto
											
											if (EDK.output & EDK_OUT_RELAY)	// rele je jiz zapnuto, generovat paket STATE_INFO
	 		 								 {
											   AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_INFO, curState, (tUInt *)&PT_ADR.X);	
											 }
											else								// rele jste neni zapnuto
                                             { 
												EDK.output |= EDK_OUT_RELAY;	// zapnout rele a generovat paket STATE_CHANGE
		 		 								AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_CHANGE, curState, (tUInt *)&PT_ADR.X);	
											 }
										   
										   #elif CORE_POW	
										     POW.output |= POW_OUT_RELAY;		// zapnout rele
										   #endif
										 }

										else if (appCB.SciTmp == 0x00)
										 {
 										   #ifdef CORE_EDK
										 	PT_ADR.X[0] = 0x81;					// adresa 1.rele
			 								curState = 0x00;					// rele vypnuto

											if (!(EDK.output & EDK_OUT_RELAY))	// rele je jiz vypnuto, generovat paket STATE_INFO
	 		 								 {
											   AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_INFO, curState, (tUInt *)&PT_ADR.X);	
											 }
											else
											 {
											   EDK.output &= ~EDK_OUT_RELAY;	// vypnout rele a a generovat paket STATE_CHANGE
	 		 								   AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_CHANGE, curState, (tUInt *)&PT_ADR.X);	
											 }

										   #elif CORE_POW	
										     POW.output &= ~POW_OUT_RELAY;	// vypnout rele
										   #endif
										 }
									break;


									// ovladani prikazem HWX_ON_FROM_IO
									case HWX_ON_FROM_IO:					// pouze prime ovladani rele, ne pres funkci FN_HWX
 										   #ifdef CORE_EDK

											PT_ADR.X[0] = 0x81;				// adresa 1.rele
			 								curState = 0x01;				// stav rele zapnuto
											
											if (EDK.output & EDK_OUT_RELAY)	// rele je jiz zapnuto, generovat paket STATE_INFO
	 		 								 {
											   AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_INFO, curState, (tUInt *)&PT_ADR.X);	
											 }
											else								// rele jste neni zapnuto
                                             { 
												EDK.output |= EDK_OUT_RELAY;	// zapnout rele a generovat paket STATE_CHANGE
		 		 								AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_CHANGE, curState, (tUInt *)&PT_ADR.X);	
											 }
										   #endif
									break;


									// ovladani prikazem HWX_OFF_FROM_IO
									case HWX_OFF_FROM_IO:														// pouze prime ovladani rele, ne pres funkci FN_HWX
 										   #ifdef CORE_EDK

											 PT_ADR.X[0] = 0x81;				// adresa 1.rele
			 								 curState = 0x00;					// rele vypnuto

											if (!(EDK.output & EDK_OUT_RELAY))	// rele je jiz vypnuto, generovat paket STATE_INFO
	 		 								 {
											   AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_INFO, curState, (tUInt *)&PT_ADR.X);	
											 }
											else
											 {
											   EDK.output &= ~EDK_OUT_RELAY;	// vypnout rele a a generovat paket STATE_CHANGE
	 		 								   AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_CHANGE, curState, (tUInt *)&PT_ADR.X);	
											 }

										   #endif
									break;


									// ovladani prikazem HWX_OFF_WITH_DELAY
									case HWX_ON_FROM_IO|HWX_OFF_WITH_DELAY:														// pouze prime ovladani rele, ne pres funkci FN_HWX
 										   #ifdef CORE_EDK
											EDK.output |= EDK_OUT_RELAY;			// zapnout rele
											EDK.counter.relay = appCB.SciTmp*10;	// predana doba sepnuti rele [x1s]

											 PT_ADR.X[0] = 0x81;					// adresa 1.rele
			 								 curState = 0x01;						// rele zapnuto
											 // generovat paket STV rele sepnuto 
	 		 								 AddReq(PRIORITY_SYS_MESSAGE | ADD_MULTIPLE | PROCESS_SCI_STATE_CHANGE, curState, (tUInt *)&PT_ADR.X);	

										   #endif
									break;


									default:
									 break;
								 } 

							break;
		
								 
					//*********************************************
					case SYS_DATA_GUI:

						// ackovat prijeti a zpracovani paketu
					//	sendAckPacket(ERR_SUCCESS);
			
						// blokovat operaci LED timeru, at sedi delka svitu pro kratke casy
						EDK.sys_flag |= FLAG_BLOCK_LED_TIMER;
			
						// vyzvednout parametry pro piskac
						EDK.buzzer.value = *((tUInt *)(gData.bufferRxD+SYS_HEADER_LEN+4));		// value BEEP
						EDK.buzzer.mask  = *((tUInt *)(gData.bufferRxD+SYS_HEADER_LEN+5));		// maska BEEP

						// vyzvednout parametry pro LED
						EDK.led.value = *((tUInt *)(gData.bufferRxD+SYS_HEADER_LEN+6));		// value LED
						EDK.led.mask  = *((tUInt *)(gData.bufferRxD+SYS_HEADER_LEN+7));		// maska LED

 						SetLedState();			// nastavit stavy LED
						SetBuzzerState();		// nastavit stav piskace

						UpdateLedState();
						UpdateBuzzerState();
						
					    // odblokovat timer
						EDK.sys_flag &= ~FLAG_BLOCK_LED_TIMER;
	
					 break;

					
			
					//*********************************************					
					default:
					  // nepodporovany paket - neznamy typ paketu
		       		  // NACK pro nezname pakety potlacen, kvuli zpetne kompatibilite
					  // sendAckPacket(ERR_SCI_UNKNOWN);					
				     break;	 

 }	// end of switch


					 
    // inicializace promennych pro dalsi paket	
    DataInitParse();

		   
 }  // konec obsluhy paketu

}	 // end of while(gRxPos)

#endif

return;	
}



/*************************************************************************
*Name:    UART0 Receive Interrupt Routine       
*Parameters:  none                   
*Returns:     none   
*Description: Interrupt routine for UART0 receive  (software int 18)
*************************************************************************/
void _uart0_receive(void) __attribute__ ((interrupt));
void _uart0_receive(void)
{
#ifdef INTERFACE_RS					// funkce je platna jen pro EDK+RS s rozhranim RS

	char _rxdata, _error;

	ir_s0ric = 0;		// clear interrupt request flag

	re_u0c1 = 0;		// Reception disabled 
		
 	// zpracovani prijateho znaku v core_bus
    // ulozi se do gRx[] odkud se dale zpracova v ParseSciRxData
    // buffer je kruhovy, pokud nebudou data vcas zpracovana bufer se zaplni a generuje se chyba

	 _rxdata = u0rbl;
     _error = u0rbh;             // Get error 

     re_u0c1 = 1;                // Reception enabled 


	 if( BusRecvByte(_rxdata) )
	//  appCB.error = ERR_SCI_BUFFER;
	 
 	BusControl.BusState &= ~BUS_FREE; 					// maze se priznak volne sbernice
	BusControl.Timer_counter = BUS_FREE_TIMEOUT;		// a nuluje se timeout pro znovu nastaveni flagu
	
#endif
}


/*************************************************************************
*Name:  SCI_PutChar
*Description: function to send one byte over SCI
*************************************************************************/
void SCI_PutChar(tUInt Data)
{		
	while(!ti_u0c1);				/* No data in U0TB register */
	u0tbl = (char)(Data);			/* Set Transmit data */

}

/*************************************************************************
*Name:  SCI_PutString
*Description: function to send string over SCI
*************************************************************************/
void SCI_PutString( tUChar *pbStrPtr )  
{  
    while( *pbStrPtr != '\0' )  
     {  
        SCI_PutChar( *pbStrPtr );  
        pbStrPtr++;  
    }  
}  


/*************************************************************************
*Name:  StvSciMessage
*Description: zpracovani/odeslani zpravy SYS_DATA_STV
*************************************************************************/
void StvSciMessage(void)
{
#ifdef INTERFACE_RS				// a rozhrani RS

  tUChar msgLen, io_len;
  tUInt pstv;
  unsigned int _ep;
  unsigned char datalen;
  
	
  GUINTRECORD		cAdr;	

	
  // kolize MAC adres na sbernici - je to odpoved na nas dotaz STV od jine jednotky, ktera ma stejnou adresu
  if( *(unsigned int *)(gData.bufferRxD+SYS_HEADER_LEN) == OPER.idAdr)
   {
	  popSCIData( );
	  appCB.error = ERR_SCI_ADDR; 
	  return;   
   }
  ////////////// konec kontroly kolize
  
  

//--------------------------------------------
// sestaveni datove casti
// hlavicka se vytvori az na konci
//-------------------------------------------- 
 switch (appCB.SciTmp)
  {
    // zakladni data nebo rozsirene data
	case 0x00:		
	case 0x01:		
 		
		msgLen=0;
		// adresa odesilatele
		gData.bufferTxD[SYS_HEADER_LEN+1] = (_gUnitAddr & 0x00FF);
		gData.bufferTxD[SYS_HEADER_LEN] = (_gUnitAddr>>8);
		msgLen+=2;

		// verze FW-HI
		gData.bufferTxD[SYS_HEADER_LEN+2] = FW_VERSION_HI;  
		// verze FW-LOW
		gData.bufferTxD[SYS_HEADER_LEN+3] = FW_VERSION_LOW;
		msgLen+=2;

		// verze HW SPEC-HI
		gData.bufferTxD[SYS_HEADER_LEN+4] = HW_SPEC_HI; 

		// verze HW SPEC-LOW (technologie cteckz + stav jumperu)
		gData.bufferTxD[SYS_HEADER_LEN+5] = EDK.hwspec_low;
    	msgLen+=2;

		//-------------------------------------------- 
		// k tomu se pridavaji rozsirene data
		//--------------------------------------------   
  		if(appCB.SciTmp == 0x01)		
  		 {	  
    	  // zkopirovat SN
		  my_memcpy( &gData.bufferTxD[SYS_HEADER_LEN+msgLen], &cfgsystem.tsn[0], 6);	
    	  msgLen+=6;
	
		  // zkopirovat MASTER ID
		  gData.bufferTxD[SYS_HEADER_LEN+msgLen] = cfgsystem.master;	
    	  msgLen++;
	
		  // zkopirovat BOOT ID
		  gData.bufferTxD[SYS_HEADER_LEN+msgLen] = cfgsystem.bootver;	
    	  msgLen++;

   		  // doplnit 6x 0x00 - nevyuzite bajty pro EDK4
		  gData.bufferTxD[SYS_HEADER_LEN+msgLen] = 0;	
    	  gData.bufferTxD[SYS_HEADER_LEN+msgLen+1] = 0;	
		  gData.bufferTxD[SYS_HEADER_LEN+msgLen+2] = 0;	
		  gData.bufferTxD[SYS_HEADER_LEN+msgLen+3] = 0;	
		  gData.bufferTxD[SYS_HEADER_LEN+msgLen+4] = 0;	
		  gData.bufferTxD[SYS_HEADER_LEN+msgLen+5] = 0;	
		  msgLen+=6;
   	    }
  	break;
  
  
	//-------------------------------------------- 
	// textovy popis ctecky
	//--------------------------------------------   
  	case 0x02:
 	  	msgLen=0;

		// adresa odesilatele
		*(tUInt*)&gData.bufferTxD[SYS_HEADER_LEN] = SWAP(_gUnitAddr);
		//gData.bufferTxD[SYS_HEADER_LEN] = (_gUnitAddr>>8);
		msgLen+=2;

		
		// zkopirovat popisku
		my_memcpy( &gData.bufferTxD[SYS_HEADER_LEN+msgLen], &cfgstitle.string[0], 16);	// 16 znaku je delka popisky
    	msgLen+=16;
	
	break;
  
   
	//-------------------------------------------- 
	// cteni globalnich poarametru pouze LOOPINP
	//--------------------------------------------   
    case 0x10:	
	  	msgLen=0;

		// adresa odesilatele
		gData.bufferTxD[SYS_HEADER_LEN+1] = (char)_gUnitAddr;
		gData.bufferTxD[SYS_HEADER_LEN] = (char)(_gUnitAddr>>8);
		msgLen+=2;

		// GCONFIG
		gData.bufferTxD[SYS_HEADER_LEN+msgLen+1] = 0;
		gData.bufferTxD[SYS_HEADER_LEN+msgLen] = 0;
		msgLen+=2;
	
		// GCONFIG1
		gData.bufferTxD[SYS_HEADER_LEN+msgLen+1] = 0;
		gData.bufferTxD[SYS_HEADER_LEN+msgLen] = 0;
		msgLen+=2;

		// LOOPINP
		gData.bufferTxD[SYS_HEADER_LEN+msgLen] = EDK.config.loopinp;
		msgLen+=1;

		// ADSKIPVALUE
		gData.bufferTxD[SYS_HEADER_LEN+msgLen] = 0;
		msgLen+=1;
	
		// PWMVALUE
		gData.bufferTxD[SYS_HEADER_LEN+msgLen] = 0;
		msgLen+=1;

		gData.bufferTxD[SYS_HEADER_LEN+msgLen] = 0;
		msgLen+=1;
		gData.bufferTxD[SYS_HEADER_LEN+msgLen] = 0;
		msgLen+=1;
		gData.bufferTxD[SYS_HEADER_LEN+msgLen] = 0;
		msgLen+=1;
	
	break;
 
	default:
	 break;
 }					// koinec switch
  
  
  // pokud je co poslat, tak poslat, pro pripad chyby
  if (msgLen)  
   {
    // pridat celkovou delku paketu a CRC nakonec
    gData.bufferTxD[5] =  (msgLen+2);		// delka paketu
    DataAddCrcMessage(  msgLen ); 			// crc podle typu STV
    msgLen+=2;

    // sestav hlavicku pro odpoved na STV paket, s RID a MAC adresou z prijate zpravy
   	DataCreateMessageHeader( SYS_DATA_STV, SWAP(reqBuffer[appCB.task].addr[1]), SWAP(reqBuffer[appCB.task].addr[0]), msgLen ); 

	// odeslani celeho paketu
   	SendPacket(SYS_HEADER_LEN + msgLen);
  }
 
#endif
}




/*************************************************************************
* MeasureSciMessage()
* Odeslani paketu SYS_STATE_MEASURE
*************************************************************************/
void MeasureSciMessage(void)
{
#ifdef INTERFACE_RS			// pouze rozhrani RS

	tUChar msgLen, io_len;
	tUInt pstv;
	unsigned int _ep;
    unsigned int firstlast;
	
	
	tUChar addr_modul;		// poradi snimace
	tUChar addr_io;			// merici kanal snimace
	tUChar data_state;		// doplnujici priznak veliciny
    
	tUChar ad_value_high;	// prenasena zprava
	tUChar ad_value_low;
	
	GUINTRECORD   PT_ADR;	
    GUINTRECORD  *ptdata;

	// ve spodnim bajtu se prenasi typ veliciny a v hornim bajtu poradi snimace, v pameti je to ale ulozeno opacne
	// pro spravne vyzvednuti parametru si pomuzeme takto
	ptdata = (GUINTRECORD*)&reqBuffer[appCB.task].parameter;		
	data_state = ptdata->VALUE.LO;				// typ veliciny ve spodnim bajtu
	addr_modul  = ptdata->VALUE.HI;				// poradi snimace v hornim bajtu parametru
    
	addr_io  = reqBuffer[appCB.task].addr[0];			// kanal snimace
    firstlast  = reqBuffer[appCB.task].addr[1];			// priznak FIRST/LAST

// hlavicka
    DataCreateMessageHeader(SYS_STATE_MEASURE|(reqBuffer[appCB.task].addr[1]&0x00ff), 0, 0, 14);  		// UNICAST paket 
	//sRIDDataCreateMessageHeader( SWAP(reqBuffer[appCB.task].parameter), SWAP(reqBuffer[appCB.task].addr[1]), SWAP(reqBuffer[appCB.task].addr[0]), msgLen ); 
   
//-----------------------------
// datova cast
//-----------------------------
	msgLen=0;
// adresa odesilatele
	gData.bufferTxD[SYS_HEADER_LEN+1] = (char)_gUnitAddr;
	gData.bufferTxD[SYS_HEADER_LEN] = (char)(_gUnitAddr>>8);
	msgLen+=2;

// ADR_MODUL
	gData.bufferTxD[SYS_HEADER_LEN+2] = addr_modul;		// poradi snimace
	msgLen+=1;

// merici kanal v ramci snimace
	gData.bufferTxD[SYS_HEADER_LEN+3] = addr_io;		// kanal
	msgLen+=1;
	
// data state - doplnujici priznak veliciny
	gData.bufferTxD[SYS_HEADER_LEN+4] = data_state;		// typ veliciny
// rezerva
	gData.bufferTxD[SYS_HEADER_LEN+5] = 0x00;
	msgLen+=2;

	// poslat hodnotu dle typu veliciny
	switch (data_state)
	 {
  	#ifdef USE_VOLT
	    case SENSOR_TYPE_VOLTAGE:
		   	ad_value_high = (char)( EDK.sensor[SENSOR_VOLT].data>>8);
		   	ad_value_low = (char)EDK.sensor[SENSOR_VOLT].data;
		 break;
  	#endif
			
	#ifdef USE_CURRENT
		case SENSOR_TYPE_CURRENT:
	 	  	ad_value_high = (char)( EDK.sensor[SENSOR_CURR].data>>8);
	 		ad_value_low = (char)EDK.sensor[SENSOR_CURR].data;
		 break;
  	#endif
  			 
	#ifdef USE_THERMO
		case SENSOR_TYPE_TEMPERATURE:
			ad_value_high = (char)( EDK.sensor[SENSOR_TEMP].data>>8);
		    ad_value_low = (char)EDK.sensor[SENSOR_TEMP].data;
		 break;
  	#endif
  	
	#ifdef USE_LUX		 
		case SENSOR_TYPE_LUX:
			ad_value_high = (char)( EDK.sensor[SENSOR_LUX].data>>8);
		    ad_value_low = (char)EDK.sensor[SENSOR_LUX].data;
		 break;
    #endif
  
	#ifdef USE_WIND
		case SENSOR_TYPE_WIND:
			ad_value_high = (char)( EDK.sensor[SENSOR_WIND].data>>8);
		    ad_value_low = (char)EDK.sensor[SENSOR_WIND].data;
		 break;
    #endif
  
 	#ifdef USE_HUM
		case SENSOR_TYPE_HUMIDITY:
			ad_value_high = (char)( EDK.sensor[SENSOR_HUM].data>>8);
		    ad_value_low = (char)EDK.sensor[SENSOR_HUM].data;
		 break;
	#endif
 
  	   default: break;
	}


	// prenasena hodnota, vyjadreni x10 (+jedno desetine misto)
	gData.bufferTxD[SYS_HEADER_LEN+6] = 0;
	gData.bufferTxD[SYS_HEADER_LEN+7] = 0;
	gData.bufferTxD[SYS_HEADER_LEN+8] = ad_value_high;
	gData.bufferTxD[SYS_HEADER_LEN+9] = ad_value_low;
	msgLen+=4;

	gData.bufferTxD[SYS_HEADER_LEN+10] = 0;
	gData.bufferTxD[SYS_HEADER_LEN+11] = 0;
	msgLen+=2;
	
	DataAddCrcMessage( 12 ); 
	msgLen+=2;

    SendPacket(SYS_HEADER_LEN + msgLen);
  
#endif
}




/*************************************************************************
*Name:  SendPacket
*Description: 
*************************************************************************/
void SendPacket(tUChar length)
{
  tUInt temp;
	
  do {
		ClearWDT();
	
		temp =  SCI_PutPacket(gData.bufferTxD, length);

		if (temp != 0)
		 {
		   BusControl.BusState &= ~BUS_FREE; 							// maze se priznak volne sbernice
		   BusControl.Timer_counter = BUS_FREE_TIMEOUT;					// a nuluje se timeout pro znovu nastaveni flagu
				   
		   if(++BusControl.Timer_counter1 >= BUS_WAIT_TIMEOUT)			// SLOUZI JAKO POCITADLO NEUSPESNYCH ODESLANI
		    {
	     	  BusControl.BusState |= BUS_TIMEOUT; 			 
	     	  BusControl.Timer_counter1 = 0;							// timeout counter
		 	}
		 }
   	 }
   while (  (temp != 0) && (!(BusControl.BusState & BUS_TIMEOUT)) );	// snazi se odeslat paket, ceka se na BUS_FREE, vypadne pouze na BUS_TIMEOUT 
																		
   BusControl.Timer_counter1 = 0;				// timeout counter
   
   if ( BusControl.BusState & BUS_TIMEOUT)		// prenos vzpadl na BUS_TIMEOUT - bezna stav pri odpojene lince );     
    {
	  BusControl.BusState &= ~BUS_TIMEOUT; 		// pokud vypadlo na BUS_TIMEOUT tak smazat flag
	}

   DataInitPacket();
   RX_InterruptEnable;

}


// ************************************************************************* 
// odeslani zpravy SYS_DATA_DLL
// osluhuje se cteni/zapis podle flagu v PID
// ************************************************************************* 
void DllSciMessage(void)
{
  tUChar msgLen, dll_len;
  tUInt	dll_index;
  GUINTRECORD dll_adr;
  tUInt status;

  // ziskat adresu ADDR_MODUl z paketu
  dll_adr.X = *((tUInt *)(gDataType+2));
  
  
//// ZAPIS /////////////////////////////////////////////
if( SWAP((reqBuffer[appCB.task].parameter)&PAC_FLAG_WRITE) ) 
 {
    switch(gDataType[0])												// rozhodnuti co to je podle ID
     {
	   // ----------------------------------------
   	   // 0x11 - zapis dat pro upload FW
   	   // ----------------------------------------
  	   case DLL_FW_DATA:												// kontrola na ID 

		dll_len = gDataType[1]-4;										// delka uzitecnych dat v paketu
		  
     	// pokud je prvni paket - nulujem ukazatel na zacatek datoveho prostoru
     	if( SWAP((reqBuffer[appCB.task].parameter)&PAC_FLAG_FIRST) )
	  	 {
		  status = BootEraseDF();
		  if (status == NO_ERROR)
		   {
			 sendAckPacket(ERR_SUCCESS);
		   }
		  else
		   {
			 sendAckPacket(ERR_SCI_READONLY);							// zapis neni mozny, nelze smazat oblast dataflash
		   }

	       appCB.SciTmp = 0; 											// nastaven bit FIRST - je to prvni paket
   		   dll_index = SWAP(*(tUInt*)&gDataType[4]);	  				// pocatecni adresa pro flashovani
		   BootInitFrame(dll_index, dll_len);
		 }
	 	
		// pokud je nastaven bit LAST (muze byt nastaven soucasne s FIRST)
		if( SWAP((reqBuffer[appCB.task].parameter)&PAC_FLAG_LAST) )		// nastaven bit LAST
	  	 {												
	       BootCopyFrame(dll_len);										// ukladat data z gDataType
		   
		   status = BootWriteFrame();									// ukoncit ukladani a vypalit data do FLASH
		   if (status == NO_ERROR)
		   {
			 sendAckPacket(ERR_SUCCESS);
		   }
		  else
		   {
			 sendAckPacket(ERR_SCI_READONLY);							// zapis neni mozny, nelze smazat oblast dataflash
		   }
		 }

		if( !(SWAP((reqBuffer[appCB.task].parameter)&(PAC_FLAG_FIRST|PAC_FLAG_LAST))) )	// neni nastaven zadny bit
	     {	
	       BootCopyFrame(dll_len);					// ukladat data z gDataType
		   sendAckPacket(ERR_SUCCESS);				// ackovat zpracovani paketu
		 }

      break;


   // ----------------------------------------
   // 0x10 - zapis MAC adresy
   // ----------------------------------------
   case DLL_MAC_DATA:										
		
//		dll_len = gDataType[1];					// delka dat v paketu
   	   if ( SnIsInitialized() == TRUE)
	    {
		   sendAckPacket(ERR_EEPROM_WRITE);		// SN je uz zapsano, hlasit chybu
		}
   	   else										// SN neni jeste zapsano, tak zapsat
	    {	
		  status = WriteSn(&gDataType[6]);
		  if (status==NO_ERROR)						
	 	   {
		     status = InitConst(1);				// provest aktualizaci MAC adresy
		     if (status != NO_ERROR)
			  {
			    sendAckPacket(ERR_EEPROM_WRITE);
			  }
			 else sendAckPacket(ERR_SUCCESS);		     
		   }
		  else sendAckPacket(ERR_EEPROM_WRITE);		     
		}


	 break;

   // ----------------------------------------
   // 0x20 - zapis emergency karet
   // ----------------------------------------
	case DLL_ECR_DATA:			
 	  #ifdef CORE_EDK
		dll_len = gDataType[1];									// delka dat v paketu
   		dll_index = gDataType[3];								// adresa pozice karty v pameti - vzit jen CHAR!
		
  
     	// pokud je to paket s priznakem FIRST tak nejdrive smazat cely prostor pameti karet
     	if( SWAP((reqBuffer[appCB.task].parameter)&PAC_FLAG_FIRST) )
	  	 {
		   // smazat cely seznam karet
 		   status = ClearAllEmergencyCards();								

	  	   if (status != NO_ERROR)
		    {
				sendAckPacket(ERR_SUCCESS);		    
		    }
		 }
		  
		// pokud je nastaven bit LAST (muze byt nastaven soucasne s FIRST)
		if( SWAP((reqBuffer[appCB.task].parameter)&PAC_FLAG_LAST) )		// nastaven bit LAST
	  	  {												
				// nedela nic
	      }

		// pokud je delka dat 6 bajtu tak je to paket bez PINU		
		if (dll_len == 0x06)
		 {
			// zapis karty do pameti, bez PINu
			status = WriteEmergencyCard(&gDataType[4], 0, dll_index);	// PIN je 0x0000
		 }
		else
		 {
		   // zapis karty s PINem
		    status = WriteEmergencyCard(&gDataType[4], ((gDataType[8]&0x00FF)|(gDataType[9]<<8)), dll_index);		
		 }

	 	
	   // kontrola stavu zapisu
		if (status==NO_ERROR)						
	 	 {
			sendAckPacket(ERR_SUCCESS);
	 	 }
		else											// chyba zapisu
		 {
			sendAckPacket(ERR_EEPROM_WRITE);
		 }

	 break;


   // ----------------------------------------
   // 0x21 - vymazani dane pozice
   // ----------------------------------------
	case DLL_ECR_REMOVE:			
 	  #ifdef CORE_EDK
		dll_index = gDataType[3];					// adresa pozice karty v pameti - vzit jen CHAR!
		status = RemoveEmergencyCard(dll_index);	// smazat zaznam na dane pozici 

	   // kontrola stavu zapisu
		if (status == NO_ERROR)						
	 	 {
			sendAckPacket(ERR_SUCCESS);
	 	 }
		else										// chyba zapisu
		 {
			sendAckPacket(ERR_EEPROM_WRITE);		 
		 }
	   #endif
	break;

#endif



	// ----------------------------------------
	// 0x0B - prednastaveni vstupu/vystupu 
	// ----------------------------------------
	case DLL_IO_PRESET:	

	 // memset(EEPROM.data, 0, sizeof(EEPROM.data));
	  //memcpy(EEPROM.data, gDataType+4, dll_len-4);

	 // pokud pozadovany sensor existuje, tak ulozit data pro nej do tabulky InputTable
	 dll_index = findSensor(dll_adr);			// vraci offset sensoru, pokud 0xFF tak nenalezeno
	 if ( dll_index != 0xFF)					// vraci offset sensoru, pokud 0xFF tak nenalezeno
	  {
	    AddInputTable(dll_index, (tUChar*)&gDataType+4);	// ulozit nastaveni pro adresu sensoru do tabulky InputTable
	    sendAckPacket(ERR_SUCCESS);
	  }
	 else										// data pro neexistujici sensor
	   {
	     appCB.error = ERR_SCI_RANGE; 
	   }
	  

	 			  
	 
				   
				   
		/*		   	   
	   
	   // kontrola stavu zapisu
		if (status == NO_ERROR)						
	 	 {
			sendAckPacket(ERR_SUCCESS);
	 	 }
		else										// chyba zapisu
		 {
			sendAckPacket(ERR_EEPROM_WRITE);		 
		 }*/
	break;


     // ----------------------------------------					   
	 // nezname ID			
     // ----------------------------------------
	  default:							
	      appCB.error = ERR_SCI_BADVALUE;
		  sendAckPacket (appCB.error);
	  break;
	
	}		// konec switch
		

	 msgLen = 0;
	 
	}

}




// ************************************************************************* 
// odeslani zpravy SYS_DATA_CFG
// ma vyznam pouze cteni
// ************************************************************************* 
void CfgSciMessage(void)
{
  tUChar msgLen, io_len;
  tUInt io_index;

  // pro identifikaci co jiz bylo odeslano slouzi promena appCB.SubMenu_tmp	   	   
  // pokud je prvni paket - nulujem ukazatel					
  if( SWAP(reqBuffer[appCB.task].parameter&PAC_FLAG_FIRST) )
   {
     appCB.SubMenu_tmp.X = 0x0000;										// prochazet nejdrive interni IO na jednotce
   }
  
  // kontrola jestli existuje dalsi IO, pokud ne dalsi nastav LAST flag a posli jen CRC
  if(!getNextIO(&appCB.SubMenu_tmp, (unsigned char)appCB.SciTmp))	
   {
     getPrewIO(&appCB.SubMenu_tmp, (unsigned char)appCB.SciTmp);
     reqBuffer[appCB.task].parameter |= SWAP(PAC_FLAG_LAST);	 
	 msgLen = 0;
   }
  else
   {	
	 // existuje dalsi IO
	 *(tUInt *)(gData.bufferTxD+SYS_HEADER_LEN) = appCB.SubMenu_tmp.X;		
    
	 // je to vystup
	 if( appCB.SciTmp )
	  {
	   *(tUInt *)(gData.bufferTxD+SYS_HEADER_LEN) |= SWAP(ADDR_OUTPUT);		// nastavit priznak vystupu	
	  }
	 // je to vstup
	 else if( appCB.SubMenu_tmp.VALUE.HI == 0)							// jedna se o interni vstupy  na ctecce
	  {
	     if (appCB.SubMenu_tmp.VALUE.LO == 3)							// prvni a druhy vstup je IN1-IN2, tedy interni vstupy
		  {																// treti vstup je TAMPER, a ten bereme jako externi, proto nastavir 0x40
		    *(tUInt *)(gData.bufferTxD+SYS_HEADER_LEN) = SWAP (0x0001);	// zmenit cislovani vstupu - stane se z nej prvni externi
			*(tUInt *)(gData.bufferTxD+SYS_HEADER_LEN) |= SWAP(0x0040);		
		  }
	  }

     msgLen = 2;
     *(tUInt *)(gData.bufferTxD+SYS_HEADER_LEN+msgLen) = SWAP(MODUL_EDK4);			// typ modulu
     msgLen += 2;
	
	// ADDR_MODE podle tabulky definic IO
	// je to vystup
	if(appCB.SciTmp)			
     {
  	   *(gData.bufferTxD+SYS_HEADER_LEN+msgLen) = getModeIO((GUINTRECORD)(appCB.SubMenu_tmp.X|ADDR_OUTPUT));		// mode - druh IO - binarni/analogovy
	 }
	// je to vstup
	else
     {
	   *(gData.bufferTxD+SYS_HEADER_LEN+msgLen) = getModeIO((GUINTRECORD)(appCB.SubMenu_tmp));	
	 }
	
	
    *(gData.bufferTxD+SYS_HEADER_LEN+msgLen+1) = 0;					// rezerva
    msgLen += 2;

    // nacist a pripojit textovy popis IO
	if( appCB.SubMenu_tmp.VALUE.HI == 0 )			// pro IO na jednotce je to jinde!!
	 {
		//todo....dodelat take v DLL a vse kolem DefaultOutStates(void) 
	 }
	
    DataAddCrcMessage( msgLen );  
    msgLen += 2;

	if(!getNextIO(&appCB.SubMenu_tmp, (unsigned char)appCB.SciTmp))		  	 // neni dalsi nastav LAST flag
     {
	   reqBuffer[appCB.task].parameter |= SWAP(PAC_FLAG_LAST);	 
	 }
  	
	getPrewIO(&appCB.SubMenu_tmp, (unsigned char)appCB.SciTmp);

   }
   
   
  // sestaveni a odeslani paketu 
  DataCreateMessageHeader( SWAP(reqBuffer[appCB.task].parameter), SWAP(reqBuffer[appCB.task].addr[1]), SWAP(reqBuffer[appCB.task].addr[0]), msgLen );  
    
  SendPacket(SYS_HEADER_LEN + msgLen);
	  
  //if( SCI_PutPacket( gData.bufferTxD, SYS_HEADER_LEN + msgLen ) != 0 )		
	//{
    // if(SCI_ResendReq()) 
	  //{
	    //AddReq(PRIORITY_TASK_MID | ADD_MULTIPLE | PROCESS_SCI_DATA_CFG, reqBuffer[appCB.task].parameter, (tUInt *)&reqBuffer[appCB.task].addr);		  
	  //}
    // else
	//  {				   
     //   packetRepeatError();
	//  }
//	}
	  	
//return;	
}



