////////////////////////////////////////////////////////////////
// 					DCF77 dekódoló unit
//				 Topor Zoltán - 2007. febr.
//			   http://www.hobbielektronika.hu/
////////////////////////////////////////////////////////////////

// #define DECODE_DATE

int parity_cou = 0;
int  dcf_index = 0;
int dcf_diff = 0;
int dcf_diff_store = 0;

struct Ttime {
	unsigned int minute,hour,sec
#ifdef	DECODE_DATE
	,year,day,month,week_day
#endif
	;
	boolean HasNewTime;
	boolean isSummer;
	boolean TimeZoneChg;
	boolean ReserveAntenna;
};
struct Ttime dcf_time;
struct Ttime time;

boolean ParityOK = false;

////////////////////////////////////////////////////////////////
void Check_dcf_time() {
////////////////////////////////////////////////////////////////
   // a téli-nyári időszámítís miatti az órás átállásnál lehet gondja 
   // bár ha egymás után kétszer bejön azt is korrigálja
   // ha az átállásra figyelmeztető jelzőbitet (16) 
   // és az előző állapotot (17-18) is figyelem megoldható ... LESZ!! 
   // egyenlőre pár perccel később áll át
   if(volt_mar_dcf) {
      // az eltérés percekben
      dcf_diff=((dcf_time.hour*60)+dcf_time.minute)-((time.hour*60)+time.minute);
      // a páros paritás ellenőrzés miatt ha egy bit marad ki paritás hibás lesz
      // ha több 2-nél mindenképpen többel fog eltérni, így a 2 perc eltérés elfogadható
      // ennél nagyobb külömbség úgyse lesz, ehez hónapokig kell dcf nélkül mennie
      // ha mégis volna a második jó csomaggal úgyis beállítja
      if(abs(dcf_diff)>2) {
         dcf_time.HasNewTime=false;
         // nincs mentett eltérés adat
         if(dcf_diff_store==0) {
            dcf_diff_store = dcf_diff;
         } else {
            // volt már egy adat, és ugyan annyival tér el mint a mostani, ez a jó
            // persze feltéve hogy két egymást követő jó paritású˙csomag nem éppen ugyanúgy sérült
            // bár ez nem valószínű, de tapasztalat szerint előfordul
			// mivel a dátumot nem figyelem ezzel a módszerrel, jellemzően a dátum mászkál el, mert a paritása két hibás bitnél OK lesz
			// azt is meg kéne oldani.... talán majd később....
			// ---- kis segítség:
			// ha valakinek van ambíciója hozzá, a dátumot összeadhatja éé+hh+nn
			// mivel a max dátum 99.12.31 ez (99+12+31=142) bőven elfér egy byte-ban, ez tárolható, és 
			// nem ugyan ez jön, a CRC OK ellenére is biztosan hibás.
			// ezzel ugyan kizárjuk az éjféli szinkronizálást, de marad mén napi 1439 lehetősége
			// szerintem megéri, mert így kisebb a valószínűsége hogy agymenés dátumra áll be
            dcf_time.HasNewTime = (dcf_diff==dcf_diff_store);
            dcf_diff_store=0;
         }
      }
   }
}

////////////////////////////////////////////////////////////////
void dcf77_alt_decode(boolean b) {
////////////////////////////////////////////////////////////////

	switch(dcf_index) {
		case 15: dcf_time.ReserveAntenna = b;					  break;
		case 16: dcf_time.TimeZoneChg = b;						  break;
		case 17: dcf_time.isSummer = b;							  break;

		case 20: ParityOK = b; parity_cou = 0;					  break;	/* ez mindig 1 ez a start */
		case 21: dcf_time.minute = b; 	if(b)   parity_cou++;	  break;
		case 22: if(b) {dcf_time.minute += 2;   parity_cou++;}	  break;
		case 23: if(b) {dcf_time.minute += 4;   parity_cou++;}	  break;
		case 24: if(b) {dcf_time.minute += 8;   parity_cou++;}	  break;
		case 25: if(b) {dcf_time.minute += 10;  parity_cou++;}	  break;
		case 26: if(b) {dcf_time.minute += 20;  parity_cou++;}	  break;
		case 27: if(b) {dcf_time.minute += 40;  parity_cou++;}	  break;
		case 28: ParityOK &= (b+parity_cou)%2==0; parity_cou = 0; break;

		case 29: dcf_time.hour = b;		if(b)   parity_cou++;	  break;
		case 30: if(b) {dcf_time.hour += 2;     parity_cou++;}	  break;
		case 31: if(b) {dcf_time.hour += 4;     parity_cou++;}	  break;
		case 32: if(b) {dcf_time.hour += 8;     parity_cou++;}	  break;
		case 33: if(b) {dcf_time.hour += 10;    parity_cou++;}	  break;
		case 34: if(b) {dcf_time.hour += 20;    parity_cou++;}	  break;
		case 35: ParityOK &= (b+parity_cou)%2==0; parity_cou = 0; break;
		#ifdef	DECODE_DATE
		case 36: dcf_time.day = b; 		if(b)   parity_cou++;	  break;
		case 37: if(b) {dcf_time.day += 2;      parity_cou++;}	  break;
		case 38: if(b) {dcf_time.day += 4;      parity_cou++;}	  break;
		case 39: if(b) {dcf_time.day += 8;      parity_cou++;}	  break;
		case 40: if(b) {dcf_time.day += 10;     parity_cou++;}	  break;
		case 41: if(b) {dcf_time.day += 20;     parity_cou++;}	  break;

		case 42: dcf_time.week_day = b; if(b)   parity_cou++;	  break;
		case 43: if(b) {dcf_time.week_day += 2; parity_cou++;}	  break;
		case 44: if(b) {dcf_time.week_day += 4; parity_cou++;}	  break;

		case 45: dcf_time.month = b;  	if(b)   parity_cou++;	  break;
		case 46: if(b) {dcf_time.month += 2;    parity_cou++;}	  break;
		case 47: if(b) {dcf_time.month += 4;    parity_cou++;}	  break;
		case 48: if(b) {dcf_time.month += 8;    parity_cou++;}	  break;
		case 49: if(b) {dcf_time.month += 10;   parity_cou++;}	  break;

		case 50: dcf_time.year = b;  	if(b)   parity_cou++;	  break;
		case 51: if(b) {dcf_time.year += 2;     parity_cou++;}	  break;
		case 52: if(b) {dcf_time.year += 4;     parity_cou++;}	  break;
		case 53: if(b) {dcf_time.year += 8;     parity_cou++;}	  break;
		case 54: if(b) {dcf_time.year += 10;    parity_cou++;}	  break;
		case 55: if(b) {dcf_time.year += 20;    parity_cou++;}	  break;
		case 56: if(b) {dcf_time.year += 40;    parity_cou++;}	  break;
		case 57: if(b) {dcf_time.year += 80;    parity_cou++;}	  break;
		case 58: ParityOK &= (b+parity_cou)%2==0;
		#endif
	}
}

////////////////////////////////////////////////////////////////
void dcf77_isr() {
////////////////////////////////////////////////////////////////
	if(TickCount > 1500) {
		//ha kimaradt egy... vagyis ez már az új perc
		//első tick-je
		TickCount = 0;	//először ez kell, mert ezutáni is idő... talán
		dcf_index = 0;
		if(!volt_mar_dcf) time.sec = 0;
		if(dcf_time.minute > 59)  ParityOk = false;
		if(dcf_time.hour > 24) 	  ParityOk = false;
		#ifdef	DECODE_DATE
		if(dcf_time.day > 31) 	  ParityOk = false;
		if(dcf_time.day < 1) 	  ParityOk = false;
		if(dcf_time.week_day > 7) ParityOk = false;
		if(dcf_time.month > 12)	  ParityOk = false;
		if(dcf_time.month < 1)	  ParityOk = false;
		if(dcf_time.year < 8)	  ParityOk = false;  //2008 előtti
		if(dcf_time.year > 99)	  ParityOk = false;
		#endif
		dcf_time.HasNewTime = ParityOk;
    if(ParityOk) Check_dcf_time();
		ParityOK = false;
	} else if(TickCount > 300) {
		//ilyenkor már tuti nincs semmi
		TickCount = 0;
	}
}

////////////////////////////////////////////////////////////////
void dcf77_get_input() {
////////////////////////////////////////////////////////////////
	//150 ms-enként hívódik meg. Ha akkor 1-es akkor 1-es jött
	//ha 0-ás lenne, akkor ilyenkor az már 0 lenne...
	//ezután hagyjuk a timert tovább ketyegni
	dcf77_alt_decode(input(PIN_B0));
	dcf_index++;
}
