/***********************************************************************/
/*                                                                     */
/*  FILE        :gpla.c                                                */
/*  DATE        :Mon, Feb 01, 2010                                     */
/*  DESCRIPTION :Main Program                                          */
/*  CPU TYPE    :Other                                                 */
/*                                                                     */
/***********************************************************************/
       
#include "iodefine.h"
#include "tables.h"
#include "macros.h"
#include "pcf8583.h"
#include "fft.h"
#include "gpla.h"
#include "menu.h"
#include "graphics.h"
#include "globvar.h"
#include "gpla.h"
#include "menu.h"
#include "math.h"
 

//--------< Glob. Prom pro gpla.c >--------------------

//---< Pole >---
volatile signed int merU0[256],merU1[256],merU2[256],merU3[256];
volatile signed int merI0[256],merI1[256],merI2[256],merI3[256];
volatile unsigned char IsNula[8];


//---< Mereni >---
volatile unsigned int UssU0,UssU1,UssU2,UssU3;
volatile unsigned int UssI0,UssI1,UssI2,UssI3;
volatile unsigned int maxU0=0,minU0=10000,maxU1=0,minU1=10000,maxU2=0,minU2=10000,maxU3=0,minU3=10000;
volatile unsigned int maxI0=0,minI0=10000,maxI1=0,minI1=10000,maxI2=0,minI2=10000,maxI3=0,minI3=10000;
volatile unsigned int u_vzorek = 0,vzorek = 0,SB=0,SSB;

//---------< Pocitadla >------------
volatile unsigned int  Cit1S = 200;  // Pocitadlo pro jednu sekundu 
volatile unsigned char Cit200mS = 20;
volatile unsigned char CitCykl;      // Citac cyklu pro mereni frekvence
volatile unsigned char ScopeCykl =0;
volatile unsigned int  ScopeVzorek =0;
volatile unsigned char CitRepeat = 10;
volatile unsigned char CitFastRepeat = 10;
volatile unsigned char StepRepeat = 5; 

//---< Time >---
volatile unsigned int shortTime,Time_Q4,StandTime=0;
volatile unsigned long Sec_Time,V_Sec_Time;
volatile unsigned char den,mes,rok,hod,min,sec;

//---< Vsehochut >---
volatile unsigned int i,m;
volatile unsigned int t1=0,t2=0;
volatile float m_frek = 0;
volatile signed int ee_stat;
volatile unsigned char rec;

unsigned char *ee_adr;
unsigned int p;

/***********************************************************************
*                          Obsluha preruseni                           *   
***********************************************************************/
//-----< CMI0 preruseni pro A/D po 10ms >-----
#pragma interrupt
void int_cmi0()
{
	Cit200mS--;
	Cit1S--;
//---< Obsluha tlacitek >---
	if(!Cit200mS){
    Cit200mS = 20;
		if(!Key){
      Key = PA.DR.BYTE.LL;     // Prectu si tlacitka
			NewKey = ((Key & 0x3e) >> 1)^0x1f;
      Key = 0;
			if(NewKey)StandTime=0;   // Pokud je neco stisknuto nebo drzeno smazu citac casu pro standby displeje 
      if(NewKey == OldKey){    // Nektere tlacitko je drzeno
        if(flag.Repeat){
					if(NewKey&0x06){     // Je zmackle tlacitko UP nebo DOWN??
						if(StepRepeat){
							StepRepeat--;
						}
						else{
					    Key = NewKey;      // Repeat je povole ulozim si tlacitka
              if(CitRepeat){
								CitRepeat--;
								StepRepeat = 5;	 
							}
						  if(!CitRepeat){
								StepRepeat = 5;
							  estep = 10;
							  if(flag.FastRepeat){
								  if(CitFastRepeat)CitFastRepeat--;
								  if(!CitFastRepeat){
								    estep = 100;	
								  }
							  }
						  }
				    }	
					}
				}
				else{  // Neni povolen Repeat Je treba kalibrace??
				  if(NewKey == 0x06){
						if(!flag.Kalibr){  // Nejsem nahodou uz v kalibraci??
  						flag.Kalibr = 1; // Je set a sipka UP pri MainMenu?? Ano je kalibr
							flag.Change = 1;
						}
					}
				}
			}
			else{
				if(!OldKey){
			    Key = NewKey;           // Ulozim si hodnotu tlacitek
				}
				OldKey = NewKey;
				CitRepeat = 5;
				CitFastRepeat = 5;
				estep = 1;
			}
			OldKey = NewKey; 
	  }
	}
//-----			
	if(Cit1S == 100){
			flag.PulSec = 1;
	}
	if(!Cit1S){
	  Cit1S = 200;
		flag.PulSec = 0;
		sec++;
		if(sec >= 60){
	    sec = 0;
	    flag.Min = 1;  // Cteni PCF je po jedne min
    }
	  if(StandTime<ParamChar[STANDTIME])StandTime++;  // cistam cas standby displeje (StandTime se smaze vzdy pri stisku tlacitek) 	
	}
	Brightness();  // Podsviceni displeje
	CMT0.CMCSR.BIT.CMF = 0;   // Smazu priznak preruseni
}

//------< TGRC (preruseni pro mereni frekvence) >---
#pragma interrupt
void int_tgrc()
{
/*  unsigned int CitInter;  // Interval pro spousteni A/D prevodniku

	if(!MTU2S.TSTR.BIT.CST4){   // sinchro
		switch(ParamChar[7]){
		  case 0: MTU2S4.TGRD = 7680;       // 50HZ
	            MTU2S4.TADCORA = 7680; 
							break;
			case 1: MTU20.TCR.BYTE = 0x02;    //P(fi)/16
			        MTU2S4.TGRD = 6400;       // 60HZ
	            MTU2S4.TADCORA = 6400; 
							break;
			case 2: frekvence = (unsigned int)(frekvence*10);  // Auto(20-70Hz)  
			        frekvence /=10;   
			        CitInter = (unsigned int)(384000/frekvence);   //384000 = 49152000/128
		          MTU20.TCR.BYTE = 0x03;    // P(fi)/64
              MTU2S4.TGRD = CitInter;
	            MTU2S4.TADCORA = CitInter; 
  		        break;                 	
		}
    ADC0.ADCR.BIT.ADST = 1;   // Single scan mode
	  ADC1.ADCR.BIT.ADST = 1;   // Single scan mode			
	}
	MTU20.TSR.BIT.TGFC = 0;   // smazu priznak preruseni
	t1 = MTU20.TGRC;
	if(t1>t2){
		m_frek += t1-t2;
	}
	else{
		m_frek += (65536 - t2) + t1;
	}
  t2 = t1;
  CitCykl--; 
	if(!CitCykl){
		m_frek /= T_Cykl;
		switch(ParamChar[7]){
		  case 0:T_Cykl = 10;              // 50Hz
			       MTU20.TCR.BYTE = 0x02;    // P(fi)/16
			case 1:T_Cykl = 12;              // 60Hz
			       MTU20.TCR.BYTE = 0x02;    // P(fi)/16
			case 2:T_Cykl = 12;              // Auto(20-70Hz)
			       MTU20.TCR.BYTE = 0x03;    // P(fi)/64	
		}
    if(MTU20.TCR.BYTE == 0x03){
		  frekvence = 768000/m_frek;
		}
		else{
		  frekvence = 3072000/m_frek;
		} 
		CitCykl = T_Cykl;
		m_frek = 0;
	}*/
	if(!MTU2S.TSTR.BIT.CST4){  // sinchro
    ADC0.ADCR.BIT.ADST = 1;   // Single scan mode
	  ADC1.ADCR.BIT.ADST = 1;   // Single scan mode			
	}
	MTU20.TSR.BIT.TGFC = 0;   // smazu priznak preruseni
	t1 = MTU20.TGRC;
	if(t1>t2){
		m_frek += t1-t2;
	}
	else{
		m_frek += (65536 - t2) + t1;
	}
  t2 = t1;
  CitCykl--; 
	if(!CitCykl){
		CitCykl = T_Cykl;
		m_frek /= T_Cykl;
	  frekvence = 3072000/m_frek;
		m_frek = 0;
	}
}
//------< Preruseni od timeru1 >-----
#pragma interrupt
void int_cmi1()
{
  CMT.CMSTR.BIT.STR1 = 0;
	for(i=0;i<128;i++){
	  sigU0_RE[i] = ((float)merU0[i+SSB] - UssU0)*IsNula[0];
		sigU0_IM[i] = 0;
		sigU1_RE[i] = ((float)merU1[i+SSB] - UssU1)*IsNula[1];
		sigU1_IM[i] = 0;
    sigU2_RE[i] = ((float)merU2[i+SSB] - UssU2)*IsNula[2];
		sigU2_IM[i] = 0;
    sigU3_RE[i] = ((float)merU3[i+SSB] - UssU3)*IsNula[3];
		sigU3_IM[i] = 0;
    sigI0_RE[i] = ((float)merI0[i+SSB] - UssI0)*IsNula[4];
		sigI0_IM[i] = 0;
    sigI1_RE[i] = ((float)merI1[i+SSB] - UssI1)*IsNula[5];
		sigI1_IM[i] = 0;
    sigI2_RE[i] = ((float)merI2[i+SSB] - UssI2)*IsNula[6];
		sigI2_IM[i] = 0;
    sigI3_RE[i] = ((float)merI3[i+SSB] - UssI3)*IsNula[7];
		sigI3_IM[i] = 0;
    if(flag.Scope){
		  if(SSB == 0 && i>1){
	      if((sigU0_RE[i-1] < 0) && (sigU0_RE[i] >= 0)){
					if(!ScopeVzorek){  // Abych si neprepsal hodnoty tak pockam na dokonceni zobrazeni
            ScopeCykl=1;
					}
	      }
		  } 
 		  if(ScopeCykl){
				// Napeti
	      PoleScope[ScopeVzorek][0] = sigU0_RE[i]*Kalibr_array[0]; 
	      PoleScope[ScopeVzorek][1] = sigU1_RE[i]*Kalibr_array[1];
	      PoleScope[ScopeVzorek][2] = sigU2_RE[i]*Kalibr_array[2];
	      PoleScope[ScopeVzorek][3] = sigU3_RE[i]*Kalibr_array[3];
        // Proud
	      PoleScope[ScopeVzorek][4] = sigI0_RE[i]*Kalibr_array[4]; 
	      PoleScope[ScopeVzorek][5] = sigI1_RE[i]*Kalibr_array[5];
	      PoleScope[ScopeVzorek][6] = sigI2_RE[i]*Kalibr_array[6];
	      PoleScope[ScopeVzorek][7] = sigI3_RE[i]*Kalibr_array[7];
			  ScopeVzorek++;
			  if(ScopeVzorek > 256){
				  ScopeCykl = 0;
			  }
		  }
		}
	}
	Pocitej();
	Suma_Value();
  if(ScopeVzorek > 256){
		switch(TypScope){  // Sem se mi to dostane jen pokud je Scope
			case 1: DrawScope(0);  // Napeti
			        break;
			case 2: DrawScope(1);  // Proud
			        break;
			case 3: DrawScopeUI();
			        break;
		}				
 	  ScopeVzorek = 0;
	}
  CMT1.CMCSR.BIT.CMF = 0;   // Smazu priznak preruseni
}
//------< Preruseni od A/D0 >-------
#pragma interrupt
void int_adi0()
{
	if(!MTU2S.TSTR.BIT.CST4){
	  MTU2S.TSTR.BIT.CST4 = 1;
	}
  ADC0.ADSR.BIT.ADF = 0;  // smazu priznak preruseni
	merU0[vzorek+SB] = ADC0.ADDR0;  // U1
	if(maxU0 < merU0[vzorek+SB])maxU0 = merU0[vzorek+SB];
	if(minU0 > merU0[vzorek+SB])minU0 = merU0[vzorek+SB];
  merU1[vzorek+SB] = ADC0.ADDR1;  // U2
	if(maxU1 < merU1[vzorek+SB])maxU1 = merU1[vzorek+SB];
	if(minU1 > merU1[vzorek+SB])minU1 = merU1[vzorek+SB];
  merU2[vzorek+SB] = ADC0.ADDR2;  // U3
	if(maxU2 < merU2[vzorek+SB])maxU2 = merU2[vzorek+SB];
	if(minU2 > merU2[vzorek+SB])minU2 = merU2[vzorek+SB];
  merU3[vzorek+SB] = ADC0.ADDR3;  // U_zero
	if(maxU3 < merU3[vzorek+SB])maxU3 = merU3[vzorek+SB];
	if(minU3 > merU3[vzorek+SB])minU3 = merU3[vzorek+SB];
  while(ADC1.ADCR.BIT.ADST){;}  // Pockam na dokonceni prevodu od A/D1 
  merI0[vzorek+SB] = ADC1.ADDR4;  // I1
	if(maxI0 < merI0[vzorek+SB])maxI0 = merI0[vzorek+SB];
	if(minI0 > merI0[vzorek+SB])minI0 = merI0[vzorek+SB];
  merI1[vzorek+SB] = ADC1.ADDR5;  // I2
	if(maxI1 < merI1[vzorek+SB])maxI1 = merI1[vzorek+SB];
	if(minI1 > merI1[vzorek+SB])minI1 = merI1[vzorek+SB];
	merI2[vzorek+SB] = ADC1.ADDR6;  // I3
	if(maxI2 < merI2[vzorek+SB])maxI2 = merI2[vzorek+SB];
	if(minI2 > merI2[vzorek+SB])minI2 = merI2[vzorek+SB];
  merI3[vzorek+SB] = ADC1.ADDR7;  // I_zero
	if(maxI3 < merI3[vzorek+SB])maxI3 = merI3[vzorek+SB];
	if(minI3 > merI3[vzorek+SB])minI3 = merI3[vzorek+SB];
	vzorek++;
	if(vzorek>127){
		MTU2S.TSTR.BIT.CST4 = 0;
	  ADC0.ADCR.BIT.ADST = 0;   // Single scan mode
	  ADC1.ADCR.BIT.ADST = 0;   // Single scan mode			
		vzorek = 0;
	  CMT.CMSTR.BIT.STR1 = 1;
		UssU0 = (maxU0 + minU0)/2;
    UssU1 = (maxU1 + minU1)/2;
    UssU2 = (maxU2 + minU2)/2;
	  UssU3 = (maxU3 + minU3)/2;
	  UssI0 = (maxI0 + minI0)/2;
    UssI1 = (maxI1 + minI1)/2;
	  UssI2 = (maxI2 + minI2)/2;
	  UssI3 = (maxI3 + minI3)/2;
	  if((maxU0-minU0)> 15)IsNula[0] = 1;
	  else IsNula[0] = 0;
	  if((maxU1-minU1)> 15)IsNula[1] = 1;
	  else IsNula[1] = 0;
	  if((maxU2-minU2)> 15)IsNula[2] = 1;
	  else IsNula[2] = 0;
	  if((maxU3-minU3)> 15)IsNula[3] = 1;
	  else IsNula[3] = 0;
    if((maxI0-minI0)> 20)IsNula[4] = 1;
	  else IsNula[4] = 0;
	  if((maxI1-minI1)> 20)IsNula[5] = 1;
	  else IsNula[5] = 0;
	  if((maxI2-minI2)> 20)IsNula[6] = 1;
	  else IsNula[6] = 0;
	  if((maxI3-minI3)> 20)IsNula[7] = 1;
	  else IsNula[7] = 0;
	  minU0 = 10000;
	  maxU0 = 0;
    minU1 = 10000;
	  maxU1 = 0;
    minU2 = 10000;
	  maxU2 = 0;
	  minU3 = 10000;
	  maxU3 = 0;
	  minI0 = 10000;
 	  maxI0 = 0;
	  minI1 = 10000;
	  maxI1 = 0;
	  minI2 = 10000;
	  maxI2 = 0;
	  minI3 = 10000;
	  maxI3 = 0;
	  if(SB == 128){
	    SB = 0;
	    SSB =128;
	  }
	  else {
	    SB = 128;
	    SSB = 0;
	  }
	}
	ADC0.ADSR.BIT.ADF = 0;   // smazu flag
}

//-----------< WDT >------------------
#pragma interrupt
void int_wdt()
{
	asm("nop");
}

//-----< Nemaskovatelne preruseni >----
#pragma interrupt
void int_nmi()
{
	asm("nop");
}
/***********************************************************************************************
  Prevod cisla na retezec
  cifra - zobrazovane cislo
  cc    - celkový počet mist vcetne des. tecky (max 7)
  dc    - pocet des. mist (max 4)
  ic    - povoluje ci zakazjuje zobrazeni znamenka (0/1), 
          to musi zohlednovat format cisla v delce retezce
  nn    - (nevyznamne nuly ne/ano) 0/1 
	za    - 0/1 stejna sirka se sobrazenyma i nezobrazenyma nevyznamnyma nulama??
	        (Proste jestli misto nul napsat mezeru nebo ne a tim je ruzna sirka pisma)      

  (cc - dc) musí být >=2
  vysledny retezec je v promenne cislo[8]

  - příkazy: 
  NumToStr(0.855,6,2,0,0);
  OLED_WriteString5x7(row,col,0xcc,cislo,0);
  - zaokrouhlí číslo na 2 des. mista a vytisknou řezec delky 6zn (včetne d.t.)
************************************************************************************************/
void NumToStr(double cifra, unsigned char cc, unsigned char dc, unsigned char ic, unsigned char nn,unsigned char za)
{
	unsigned char nci[15];   
  unsigned long px;
  unsigned sig=0;
  unsigned char i,j,p=0;
  float pul = 5;

  if (cifra>0) sig = 1;
  if (cifra<0) {
    sig = 2;
    cifra = -cifra;
  }

  if (sig) {                                     // cisla ruzna od 0 budeme zaokrouhlovat
    for(i=0; i<=dc; i++) {                       // "vyrobime" o 1 des. misto vice kvuli zaokrouhleni
      cifra *= 10;                               // posledni des. misto se pak nezobrazuje 
      pul /= 10;                                 // pripravime si cislo pro zaokrouhleni (0.5, 0.05, ...) 
    }
    cifra += pul;                                // zde se pricte oprava na zaokrouhleni
    px = (unsigned long)cifra;                   // zaokrouhlime na cele cislo
  }
  else px = 0;

  nci[0] = 0;
  if (px >= 1000000) {                         // miliony
    nci[1] = (unsigned char)(px/1000000); 
    px -= 1000000 * (unsigned long)nci[1];
  }
  else nci[1] = 0;

  if (px >= 100000) {                          // statisice 
    nci[2] = (unsigned char)(px/100000);
    px -= 100000 * (unsigned long)nci[2];
  }
  else nci[2] = 0;

  if (px >= 10000) {                            // desetitisíce
    nci[3] = (unsigned char)(px/10000);
    px -= 10000 * (unsigned long)nci[3];
  }
  else nci[3] = 0;

  if (px >= 1000) {
    nci[4] = (unsigned char)(px/1000);
    px -= 1000 * nci[4];
  }
  else nci[4] = 0;

  if (px >= 100) {
    nci[5] = (unsigned char)(px/100);
    px -= 100 * (unsigned long)nci[5];
  }
  else nci[5] = 0;

  if (px >= 10) {
    nci[6] = (unsigned char)(px/10);
    px -= 10 * (unsigned long)nci[6];
  }
  else nci[6] = 0;

  if (px >= 1) {
    nci[7] = (unsigned char)px;
    px -= (unsigned long)nci[7];
  }
  else nci[7] = 0;

  cislo[cc+1] = 0x00;                          // ukoncovaci nula retezce
  for(i=0; i<dc; i++) {                        // zapiseme desetinnou cast
    cislo[cc-i] = nci[6-i] + 0x30;
  }
  if (dc) {
    cislo[cc-i] = ',';                         // des. tecka
    j=2;
  }
  else j=1;

  for(i=0; i<(cc-dc-j+2); i++) {               // zapise se cela cast
    cislo[cc-dc-j-i+1] = nci[6-dc-i] + 0x30;   // na miste jednotek piseme i nevyznamne 0
  }
  if (dc) j = cc-dc-1;
  else j = cc-dc;
  for(i=0; i<j; i++) {               
    if (cislo[i]>0x30) {
			break;
    }
    else {
      if (nn) cislo[i] = '0';                   // piseme nevyznamnou nulu
      else{
				   cislo[i] = 0xA4;  
				   p=i;
			}                                  // misto nevyznamne nuly - mezera
    }  
  }
  if (ic) {
    switch (sig) {
      case 0: cislo[p] = 0xff;                    // znak " "
              break;
      case 1: cislo[p] = '-';                    // znak "-"
              break;
    }
  }
	p = 0;
	if(!za){
	  for(i=0;i<cc;i++){
      if(cislo[i]==0xa4)p++;
		}
		if(p){ 
		  if(p==(cc+1)){
		    cislo[0]='0'; // cislo je 0 tak zobrazim pouze 0
			  cislo[1]=0;  // zarazka	
		  }
		  else{ 
		    for(i=0;i<cc;i++){
		      cislo[i]=cislo[p+i];	
		    }
		    cislo[cc]=0;  // zarazka
		  } 	
	  }
	}
}
/************************************************************************
*                     ---< Find_Min_Max >---                            *
*                     Najdu maxima a minima                             *
************************************************************************/
void Find_Min_Max(void)
{
  unsigned char i;
	for(i=0;i<4;i++){
    if(MaxVal[0][i] < ShowVal[0][i])MaxVal[0][i]=ShowVal[0][i];  // Max L-N
    if(MinVal[0][i] > ShowVal[0][i])MinVal[0][i]=ShowVal[0][i];  // Min L-N

    if(MaxVal[1][i] < ShowVal[1][i])MaxVal[1][i]=ShowVal[1][i];  // Max L-L
    if(MinVal[1][i] > ShowVal[1][i])MinVal[1][i]=ShowVal[1][i];  // Min L-L
 
    if(MaxVal[2][0] < ShowVal[8][1])MaxVal[2][0]=ShowVal[8][1];    // Max frekvence 
    if(MinVal[2][0] > ShowVal[8][1])MinVal[2][0]=ShowVal[8][1];    // Min frekvence

    if(MaxVal[3][i] < ShowVal[6][i])MaxVal[3][i]=ShowVal[6][i];    // Max CosFi 
    if(MinVal[3][i] > ShowVal[6][i])MinVal[3][i]=ShowVal[6][i];    // Min CosFi
	}
}
/************************************************************************
*										              Delay                                 *
*                           vstup: pocet uS                             *
************************************************************************/
void delay(int spozdeni)
{
  unsigned int cit1,cit2;

	for( cit1=0; cit1<spozdeni ; cit1++){
	  for( cit2=0; cit2<0x197; cit2++ ){
			asm("nop");
		}  // 1uS
	}
}


/****************************************************************************************************
   - obsluha reálného času v hlavni smycce
*****************************************************************************************************/
void ir_time (void)
{
  unsigned char buf[7],rok_mod;
  unsigned char *ee_data;
  unsigned int p;

  ee_data = (unsigned char *)&buf[0];
	p = pcf_another_read(0,7,ee_data);
	if (buf[0]&0x03) {
    buf[0] = 0;
    p = pcf_another_write(0,1,ee_data);
  }
  ee_data = (unsigned char*)&rok_mod;
  p = pcf_another_read(Adr_rok,1,ee_data);
  sec = BCD_TO_BIN(buf[2]);
  min = BCD_TO_BIN(buf[3]);               // aktualizuje se cas
  hod = BCD_TO_BIN(buf[4]);
  if ((min==0)||(min==15)||(min==30)||(min==45)) {
    priznak.Q4 = 1;
  }
  shortTime = 100*hod + min;
  if ((hod==2)||(hod==3)){
	  Changetime();                         // pokud je třeba, udělá přechod času
  }
  mes   = BCD_TO_BIN(buf[6]&0x1f);
  den   = BCD_TO_BIN(buf[5]&0x3f);
  rok   = (buf[5]>>6)+rok_mod;
  if (!hod&&!min) {
    if ((den==1)&&(mes==1)) {
      priznak.ChangeDate = 1;             // najdou se nová data přechodů
      if (!(buf[5]>>6)) {
        rok_mod += 4;
        ee_data = (unsigned char*)&rok_mod;
        p=pcf_another_write(Adr_rok,1,ee_data);
      }
    }
	}
}

/*********************************************************************************************
 Podle aktualniho casu a data v short formatu rrrrrrrmmmmddddd (16 bitu) nastavuje priznak casove zony:
 stredoevr. cas ZoneTime = 0,  letni cas ZoneTime = 1
 příznak ZoneTime obsahuje stav před změnou zóny
 Vraci příznak zony
**********************************************************************************************/
unsigned char SetZone(void)
{
  unsigned char l_ZoneTime,*EEdata, p;
  unsigned int aktualdat,OverTime[2];
 
  // prevedeme aktualni datum na short typ
  aktualdat = shortdat((100*(unsigned int)den) + (unsigned int)(mes));

  // nacteme z EE_prom aktualni casove prechody
  EEdata = (unsigned char *)&OverTime[0];
  p = eep_another_read(EEadr_OVERTIME,4,EEdata);

	l_ZoneTime = 0;                                                          // začneme jakoby v zimním čase
	if ((aktualdat>OverTime[T_SEC_LEC])&&(aktualdat<OverTime[T_LEC_SEC ])) { // urcite jsme v letní zóně
		l_ZoneTime = 1;
	}
	else {                                                                   // bud jsme v zimnim, nebo v prechodu
		if ((aktualdat==OverTime[T_SEC_LEC])&&(hod>=2)) {        // jsme ve dni a hodine přechodu na letní čas
			l_ZoneTime = 1;                                                      // prechazime do letniho casu, nebo v nem zustaneme
		}
		else {
  		if ((aktualdat==OverTime[T_LEC_SEC])&&(hod<3)) {
    		if (flag.ZoneTime) l_ZoneTime = 1;
      }	
    }	
	}	
	return(l_ZoneTime);						
}	
/***********************************************************************************************
 kontrola pro přechod času - je-li třeba, udělá ho
 prijde sem pri prechodu kazde nove hodiny
 "flag.ZoneTime" obsahuje na počátku příznak času (0-SEČ, 1-LEČ) pred kontrolou
 po ukončení procedury obsahuje nový aktuální stav
************************************************************************************************/
void Changetime (void)
{	
  unsigned char ZoneTime, flag_ZoneTime;

  if (flag.ZoneTime) flag_ZoneTime = 1;
  else flag_ZoneTime = 0;

	ZoneTime = SetZone();                  // aktuální stav časové zony
	if (!(ZoneTime==flag_ZoneTime)) {      // porovname s poslednim stavem, zjistujeme zmenu
    if (ZoneTime) flag.ZoneTime = 1;	   // aktualizace RAM
    else flag.ZoneTime = 0;
		if (ZoneTime) {							         // priznak prechodu na letni cas					
			hod += 1;
		}
		else {
			hod -= 1;												   // prechazi se na SE cas
		}		
	}	
}
/*****************************************************************************************************************
 vraci TRUE je-li rok prestupny
*****************************************************************************************************************/
unsigned char PrestupnyRok(unsigned char Rok)
{
  
  if (Rok%4) return FALSE;
  return TRUE;
}

/*****************************************************************************
 Prevede datum z formatu rrrrrrrmmmmddddd (16 bitu) na format 100*den + mes
*****************************************************************************/
unsigned int denmesdat(unsigned int adatum)
{
  unsigned char tden, tmes;
  
  tden = (unsigned char)(adatum & 0x001f);
  tmes = (unsigned char)((adatum & 0x01f0)>>5);
  return(100*(unsigned int)tden + (unsigned int)tmes);
}   
/**************************************************************************
*                                ---< DayInMonth >---                     *
**************************************************************************/                                                
unsigned char DayInMonth (unsigned char Mesic, unsigned char Rok)
{
  return MaxDayMonth[Mesic-1] + (Mesic == 2 && PrestupnyRok(Rok));
}

/*****************************************************************************
 Prevede datum z formatu 100*den + mes na format rrrrrrrmmmmddddd (16 bitu).
 Rok je zde uveden jen poslednim dvojcislim.
 Pouzije aktualni rok v promenne year
*****************************************************************************/
unsigned int shortdat(unsigned int adatum)
{
  unsigned int tdatum;
  
  tdatum = rok<<9;
  tdatum |= (adatum - 100*(adatum/100))<<5;
  tdatum |= adatum/100;
  return(tdatum);
}   
/*****************************************************************************
 Procedura najde mez pro vypocet noveho data prechodu v danem roce
 (pro prechod mezi LC a SEC) 

 Vstup : aktualni datum ve formatu 100*den+mes
 Vystup: mezni hodnota dne v mesici pro vypocet prechodu
*****************************************************************************/
unsigned char Mez(unsigned int adatum, unsigned int arok)
{
  unsigned char tMaxDen, aMez=0, tDen, tMes;
  unsigned int   tdatum;
  
  tdatum = denmesdat(adatum);         // prevod formatu data na 100*den+mes
  tDen = (unsigned char)(tdatum/100);
  tMes = (unsigned char)(tdatum - 100*(unsigned int)tDen);
  tMaxDen = DayInMonth(tMes,arok);    // najde pocet dnu v mesici
  if ((tDen-7)<=0) {
    aMez = 7;
  }
  else {
    if ((tDen-14)<=0) {
      aMez = 14;
    }   
  }     
  switch (tMaxDen) {
    case 28:
    case 29:  if ((tDen-21)<=0) aMez = 21;
              else aMez = 28;
                if (PrestupnyRok(arok))  aMez =29;
              break;
    case 30:  if ((tDen-23)<=0) aMez = 23;
              else aMez = 30;
              break;
    case 31:  if ((tDen-24)<=0) aMez = 24;
              else aMez = 31;
  }     
  return (aMez);  
}

/*****************************************************************************
 Procedura najde nova data pro prechody casu v aktualnim roce.
 Volá se po resetu, přechodu do nového roku nebo nastavení jiného roku v menu
 Vychazi z default hodnot DEF_S_L, DEF_L_S 
*****************************************************************************/
void Changeovertime(void)
{	
  unsigned char i, tden, pocetlet, MezPrechodu, trok, *EEdata, p;
  unsigned int OverTime[2];
  
  OverTime[0] = DEF_S_L;                // default hodnoty stanovující pravidlo
  OverTime[1] = DEF_L_S;                // jsou ve formatu ShortDate
  pocetlet = rok - (DEF_S_L>>9);
  for (i = 0; i < pocetlet; i++) {
    OverTime[0] += 0x0200;              // vezme se dalsi rok
    OverTime[1] += 0x0200; 

    // nejprve pro prechod S->L
    trok = (OverTime[T_SEC_LEC]>>9);
    MezPrechodu = Mez(OverTime[T_SEC_LEC],trok);  // urci se mez pro prechod
    if (PrestupnyRok(trok)) {             
      OverTime[T_SEC_LEC]-=1;           // odecte se dalsi den pro prechod casu
    }   
    OverTime[T_SEC_LEC]-=1;             // odecte se den
    tden = OverTime[T_SEC_LEC]&0x001f;  
    tden += 7;                          // zkus posunout o týden
    if (tden <= MezPrechodu) {
      OverTime[T_SEC_LEC] +=7;
    }   
    // totez pro prechod L->S
    trok = (OverTime[T_LEC_SEC]>>9);
    MezPrechodu = Mez(OverTime[T_LEC_SEC],trok);// urci se mez pro prechod
    if (PrestupnyRok(trok)) {             
      OverTime[T_LEC_SEC]-=1;           // odecte se dalsi den pro prechod casu
    }   
    OverTime[T_LEC_SEC]-=1;             // odecte se den
    tden = OverTime[T_LEC_SEC]&0x001f;  

    tden += 7;                          // zkus posunout o týden
    if (tden <= MezPrechodu) {
      OverTime[T_LEC_SEC] +=7;
    }   
  }   
  EEdata = (unsigned char *)&OverTime[0]; // ulozit nove hodnoty do EEprom
//  p = EE_Write(Con_EE,EEadr_OVERTIME,EEdata,4);            
}   


/*****************************************************************************
Procedura prevede datum a cas na hodnotu long v sekundach. 
Pocatkem je 1.1.2000
*****************************************************************************/
void ConvertDateTime(void)
{
  unsigned int P_D;
  unsigned char i;
  
  P_D = (unsigned int)rok*365+(rok/4+1);
  for (i=1; i<mes; i++) {
    P_D += (MaxDayMonth[i-1]+(i==2&&PrestupnyRok(rok)));
  }
  P_D += den;
  Sec_Time = (((unsigned long)P_D*24+hod)*60+min)*60+sec;
}
//--------------------< BCD_TO_BIN >---------------------
unsigned char BCD_TO_BIN ( unsigned char bcd )
{
   return (( bcd & 15 ) + (( bcd >> 4 )*10));
}

//--------------------< BIN_TO_BCD >---------------------
unsigned char BIN_TO_BCD ( unsigned char bin )
{
   return ((( bin / 10 ) << 4 ) + ( bin % 10 ));
}
/****************************************************************************
*                           ---< show_date >---                             *
*                      vstup: xstart - kde se ma zobrazit v ose x           *
*                             ystart - kde se ma zobrazit v ose y           *
*                             color  - barva pisma                          *
                              color_screen - barva pozadi                   *
*****************************************************************************/
void show_date(unsigned int xstart, unsigned int ystart,unsigned int color,unsigned int color_screen)
{
  unsigned char datum[11];
  unsigned char i=0,m=0;
	unsigned int year = 2000;

	for(i=0;i<9;i++){
		datum[i] = 0xa4;  // smazu si reg.
	}
	datum[10] = 0;      // Zarazka pro zobrazeni
	year+=rok;
	NumToStr(year,3,0,0,0,1); // prevedu rok
  for(i=0;i<4;i++){
	  datum[9-i] = cislo[3-i];
	}
  datum[5] = '.';
	NumToStr(mes,1,0,0,1,1); // prevedu mesic
	if(cislo[0] == 0x30){  // 0x30 -> 0
		datum[4] = cislo[1];
    m = 3;
	}
	else{
    for(i=0;i<2;i++){
	  	datum[4-i] = cislo[1-i];
	  }
		m=2;
	}
  datum[m] = '.';
	m--;
  NumToStr(den,1,0,0,1,1);  // prevedu den
  if(cislo[0] == 0x30){   // 0x30 -> 0 
		datum[m] = cislo[1];
	}
	else{
    for(i=0;i<2;i++){
	  	datum[m-i] = cislo[1-i];
	  }
	}
  WriteText(&datum[0],xstart,ystart,color,color_screen,3);
}
/**************************************************************
*                   ---< show_time >---                       *
*        vstup: xstart - kde se ma zobrazit v ose x           *
*               ystart - kde se ma zobrazit v ose y           *
*               color  - barva pisma                          *
*               color_screen - barva pozadi                   *
**************************************************************/
void show_time(unsigned int xstart, unsigned int ystart,unsigned int color,unsigned int color_screen)
{
	unsigned char hodin[6];
  unsigned char i=0;

	for(i=0;i<6;i++){
		hodin[i] = 0;
	}
	NumToStr(hod,1,0,0,1,1);  // prevedu hod
  for(i=0;i<2;i++){
	  hodin[i] = cislo[i];
	}
	if(flag.PulSec){  // Blikani dvojteckou po 1S 
	  hodin[2] = ':';
	}
	else{
		hodin[2] = 0x20;
  }
	NumToStr(min,1,0,0,1,1); // prevedu min
  for(i=0;i<2;i++){
	  hodin[3+i] = cislo[i];
	}
	WriteText(&hodin[0],xstart,ystart,color,color_screen,3); 
}
/*********************************************************************
*                    ---< Brightness >---                            *
*              Ridi veskere podsviceni displeje                      *
*********************************************************************/
void Brightness(void)
{
/*  unsigned char i;
  if(StandTime == ParamChar[STANDTIME]){  // Standby podsviceni displeje
    if(!ParamChar[STABRIGHT]){  // 0% vypnu displej
			// vypnout displej
		}
		else{
		  if(ParamChar[STABRIGHT] == 100){  // 100%
			  TGRC = 0;	
			}	
			else{  // Ostatni %
				TGRC = 15360/ParamChar[STABRIGHT];
			} 
		} 
	}
	else{  // podsviceni pri manipulaci s analyzatorem
	} */
}
/*********************************************************************
*                     ---< MakeReset >---                            *
*                     Nahrani def. hodnota                           *
*********************************************************************/
void MakeReset(void){
//---< ParamChar >---
	ParamChar[0] = 0xe0; // Scope Napeti
	ParamChar[1] = 0xe0; // Scope Proud
	ParamChar[2] = 0x80; // Scope Proud	
	ParamChar[Typ_U] = 0;    // Typ_U def 3f
//---< ParamInt >---
  ParamInt[0] = 0;     // Prevod traf napeti sec
	ParamInt[1] = 0;     // Prevod traf napeti sec
  ParamInt[2] = 0;     // Prevod traf proudu pri
	ParamInt[3] = 0;     // Prevod traf proudu pri

//---< ParamFloat >---

}
/********************************************************************
*                        ---<LoadEEP>---                            *
*                   Nactu hodnotz z eeprom                          *
********************************************************************/
void LoadEEP(void)
{
	
	unsigned char *ee_adr;
	unsigned char i;
//---< Nactu kalibraci >---
  // Napeti
  ee_adr= (unsigned char *)&Kalibr_array[0];
	eep_another_read(ee_kal_U0,4,ee_adr);	
  ee_adr= (unsigned char *)&Kalibr_array[1];
	eep_another_read(ee_kal_U1,4,ee_adr);	
  ee_adr= (unsigned char *)&Kalibr_array[2];
	eep_another_read(ee_kal_U2,4,ee_adr);	
  ee_adr= (unsigned char *)&Kalibr_array[3];
	eep_another_read(ee_kal_U3,4,ee_adr);	

  // Proudy
  ee_adr= (unsigned char *)&Kalibr_array[4];
	eep_another_read(ee_kal_I0,4,ee_adr);	
  ee_adr= (unsigned char *)&Kalibr_array[5];
	eep_another_read(ee_kal_I1,4,ee_adr);	
  ee_adr= (unsigned char *)&Kalibr_array[6];
	eep_another_read(ee_kal_I2,4,ee_adr);	
  ee_adr= (unsigned char *)&Kalibr_array[7];
	eep_another_read(ee_kal_I3,4,ee_adr);	

  // Z prijatych hodnot vypoctu kalibraci vykonu	
  P0_kalibr = Kalibr_array[0]*Kalibr_array[4];
  P1_kalibr = Kalibr_array[1]*Kalibr_array[5];
  P2_kalibr = Kalibr_array[2]*Kalibr_array[6];
	
  // Prevody transformatoru napeti
  ee_adr= (unsigned char *)&ParamFloat[0];
	eep_another_read(ee_nap_TrSec,4,ee_adr);	
  ee_adr= (unsigned char *)&ParamFloat[1];
	eep_another_read(ee_nap_TrPri,4,ee_adr);	
  if(ParamFloat[0] && ParamFloat[1]){
		ParamChar[5] = 1; // pokud jsou prevody >0 jsou pouzity trafa zohlednim v menu
		for(i=0;i<4;i++){
  	  Kalibr_array[i]*=(ParamFloat[1]/ParamFloat[0]);	
		}
	}
  else ParamChar[5] = 0;

 // Prevody transformatoru proudu
  ee_adr= (unsigned char *)&ParamFloat[2];
	eep_another_read(ee_pro_TrSec,4,ee_adr);	
  ee_adr= (unsigned char *)&ParamFloat[3];
	eep_another_read(ee_pro_TrPri,4,ee_adr);	
  if(ParamFloat[2] && ParamFloat[3]){
		ParamChar[6] = 1; // pokud jsou prevody >0 jsou pouzity trafa zohlednim v menu
		for(i=4;i<8;i++){  //  kalibr proudu je az od 4
  	  Kalibr_array[i]*=(ParamFloat[3]/ParamFloat[2]);	
		}
	}
  else ParamChar[6] = 0;

  // Nactu frekvenci
  ee_adr= (unsigned char *)&ParamChar[7];
	eep_another_read(ee_Frekvence,1,ee_adr);	
  if(!ParamChar[7])T_Cykl = 10;
	else T_Cykl = 12;
}
/*********************************************************************
*                             Main                                   *
*********************************************************************/

void main(void){


//-----------< Nebeh >---------------------
 	set_interrupt(0);  // Povoleni preruseni
 	LcdInit();  // Inicializace LCD
	CleanScreen(0xffff);  // Smazu LCD (Zatim nechat pak uvidim zda to bude potreba)
	MakeReset();
 	MenuDef();
  FindMenu();
	flag.Change = 1;
	flag.NewScreen = 1;
	flag.TriFaze = 0;
 	LoadEEP();       // Nactu eeprom do pameti
  DrawBox(0,0,640,45,blue1);  // Horni pruh
	T_Cykl = 10;
	m_frek = T_Cykl;
	ColorPhase[0] = red1;    // Napeti U1
	ColorPhase[1] = green1;  // Napeti U2
	ColorPhase[2] = blue5;   // Napeti U3
	ColorPhase[3] = grey2;   // Napeti U4

	ColorPhase[4] = red2;    // Proud I1
	ColorPhase[5] = green3;  // Proud I2
	ColorPhase[6] = blue6;   // Proud I3
	ColorPhase[7] = 0x0fff;  // Proud I4
//--------------------------------------------------------------------------------------------
//-------------------------------< Na zkousku >-----------------------------------------------	
  for(i=0;i<10;i++){
	  for(m=0;m<4;m++){
      MaxVal[i][m]=0;
			MinVal[i][m]=10000000;			
		}	
	}
	ParamChar[BRIGHT]    = 100;
  ParamChar[STABRIGHT] = 10; 
	ParamChar[STANDTIME] = 5;
 
/*ShowVal[0][0] = 2000000;
  ShowVal[0][1] = 2000000;
	ShowVal[0][2] = 2000000;
	ShowVal[0][3] = 2000000; */
/*
	ShowVal[0][0] = 300;
  ShowVal[0][1] = 300;
	ShowVal[0][2] = 300;
	ShowVal[0][3] = 300; 
*/

	flag.Min = 1;
	countVal = T_Cykl;
  ee_stat = pcf_write(Adr_rok,10); // rok
  ee_stat = pcf_write(0x06,0x12);  // mes
  ee_stat = pcf_write(0x05,0x31);  // den
	ee_stat = pcf_write(0x03,0x58);  // min
  ee_stat = pcf_write(0x04,0x23);  // hod
  P0_kalibr = 0.00275, P1_kalibr = 0.00275, P2_kalibr = 0.00275;
//--------------< Hlavni smycka >----------
	while(1){
		if(!flag.Kalibr){
		  Tlacitka();  // Obsluha tlacitek
		  Zobraz();			
    }
	  else{  // kalibrace
		  if(flag.Change){  // Abych si smazal pouze jednou(nastavuje se v preruseni kdyz se zjisti ze je kalibrace)
		    CleanScreen(white);
				flag.Change = 0;
			}
      if(!flag.Unlock)VerifyPassword(CAL_PASS);
      else{
			  Kalibrace();	
			}
		}
		if(flag.Min){
		  flag.Min = 0;
      ir_time();   // Nactu cas z PCF
		  ConvertDateTime();
	  }
	  if(priznak.ChangeDate){
		  priznak.ChangeDate = 0;
		  Changeovertime();
	  }
		show_time(597,8,white,blue1);  // Zobrazeni casu v hornim liste
	  show_date(560,25,white,blue1);  // Zobrazim datum 	 
	}
}




