//*****************************************************************************
// cDCF77
// ****************************************************************************
// Grundlagen DCF77                                             (c) Wikipedia
// ****************************************************************************
// Das Trägersignal von 77,5 kHz ist in Frequenz und Phasenlage mit der 
// steuernden primären Atomuhr synchronisiert und besitzt deshalb nur 
// geringe Abweichungen von der Sollfrequenz. Über einen Tag sind das weniger 
// als relativ 2x10exp-12, im Mittel über 100 Tage um weniger als 
// relativ 2x10exp-13.
// Es kann somit auch ohne Auswertung der Zeitinformation als Eichfrequenz 
// für sehr genaue Hoch- und Niederfrequenzgeneratoren benutzt werden.
//
// ****************************************************************************
// Zeitinformation
// ****************************************************************************
// Amplitudenmodulierte Sendeleistung von DCF77 als Funktion der Zeit
//
// Die Zeitinformationen werden als digitales Signal zusätzlich zur Normal-
// frequenz 77,5 kHz übertragen. Das geschieht durch negative Modulation des 
// Signals - Absenken der Trägeramplitude auf etwa 15 % - im Sekundentakt.
//           ******************************************
// Der Beginn der Absenkung liegt jeweils auf dem Beginn der Sekunden 0 bis 58 
// innerhalb einer Minute. In der letzten Sekunde erfolgt keine Absenkung, 
// wodurch die nachfolgende Sekundenmarke den Beginn einer Minute kennzeichnet 
// und der Empfänger synchronisiert werden kann. Die Länge der Amplituden-
// absenkungen am Beginn der Sekunden steht jeweils für den Wert eines binären 
// Zeichens: 
//                  100 ms Absenkung stehen für den Wert |0|
//                  200 ms                  für          |1|

// Damit stehen innerhalb einer Minute 59 Bit für Informationen zur Verfügung.

/******************************************************************************
	Bit  Bedeutung               Wertig-  Bit  Bedeutung             Wertig-
                                  keit                                keit
 ******************************************************************************
	0 - Minutenbeginn               LOW | 30   Stunden Einer              2
	1 - Reserve                         | 31   Stunden Einer              4
	2   Reserve                         | 32   Stunden Einer              8
	3   Reserve                         | 33   Stunden Zehner ********** 10
	4   Reserve                         | 34 - Stunden Zehner            20
	5   Reserve                         | 35 P PRÜFBIT 2 __________________
	6   Reserve                         | 36 - Kalendertag Einer ******** 1
	7   Reserve                         | 37   Kalendertag Einer          2
	8   Reserve                         | 38   Kalendertag Einer          4
	9   Reserve                         | 39   Kalendertag Einer          8
 10   Reserve                         | 40   Kalendertag Zehner ****** 10
 11   Reserve                         | 41 - Kalendertag Zehner        20
 12   Reserve                         | 42 - Wochentag  (MO=1   ...     1
 13   Reserve                         | 43   Wochentag        ...       2
 14 - Reserve                         | 44   Wochentag    ... SO=7 )    4
 15 - Reserveantenne                  | 45 - Monat Einer  ************  1
 16 - Zeitumstellung Ankündigung      | 46   Monat Einer                2
 17 - Zeitzonenbit 1                  | 47   Monat Einer                4
 18 - Zeitzonenbit 2                  | 48   Monat Einer                8
 19 - Schaltsekunde Ankündigung       | 49 - Monat Zehner ************ 10
 20 - Telegrammbeginn            HIGH | 50   Jahr Einer   ************  1
**********************"***************| 51   Jahr Einer                 2
 21 - Minuten Einer  ************   1 | 52   Jahr Einer                 4
 22   Minuten Einer                 2 | 53   Jahr Einer                 8
 23   Minuten Einer                 4 | 54   Jahr Zehner  ************ 10
 24   Minuten Einer                 8 | 55   Jahr Zehner               20
 25   Minuten Zehner ************  10 | 56   Jahr Zehner               40
 26   Minuten Zehner               20 | 57 - Jahr Zehner               80
 27 - Minuten Zehner               40 | 58 P PRÜFBIT 3 __________________
 28 P PRÜFBIT 1 _____________________ | 59 - keine Austastung            
 29 - Stunden Einer *************   1 | _________________________________

*************************************************************************/
	#ifndef DCF77_HPP
	#define DCF77_HPP

	#define  LPM(i) (__LPM_classic__(i))
	
	#include<cClock.h>
	#include<avr/pgmspace.h>


	namespace Mcucpp {
//*****************************************************************************

	static const uint8_t PROGMEM BitNo[] = {
//******************************************************************
		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,       // minute   7 
		0xFF,                                           // parity   1 
		0x10, 0x11, 0x12, 0x13, 0x14, 0x15,             // hour     6 
		0xFF,                                           // parity   1 
		0x20, 0x21, 0x22, 0x23, 0x24, 0x25,             // day      6 
		0x30, 0x31, 0x32,                               // weekday  3 
		0x40, 0x41, 0x42, 0x43, 0x44,                   // month    5 
		0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // year     8 
		0xFF };                                         // parity   1 
//******************************************************************

	static const uint8_t PROGMEM BitWeight[] = 
//***********************************************
	{ 1, 2, 4, 8, 10, 20, 40, 80 };              // BCD


	template < class SIG,                        // DCF77 signal input | TPin
						 class LED,                        // DCF77 debug LED    | TPin
						 class Display,                    // display
						 class TimeBase  //,               // precise sec
//***********************************************
> class cDCF77 : public cClock<Display,TimeBase> {
//***********************************************
public:
	static uint8_t _pulse;                       // extern init is mandatory
	static uint8_t _period;                      // ...

	static uint8_t _error  ;                     // extern init is mandatory
	static uint8_t _synchronize ;                // ...
                                    
	static sTimeDate _newtimedate;               // extern init is mandatory
//static sTimeDate     _timedate;              // cClock.h

	cDCF77 () {                                  // constructor
//***********************************************
		SIG::SetDirRead();                         // DCF77 input pin
		LED::SetDirWrite();                        // DCF77 debug LED

	 _error       = 0;                           // extern init is mandatory
	 _synchronize = 0;                           // ...
	}

	static void Init() {
//***********************************************
		SIG::SetDirRead();                         // DCF77 input pin
		LED::SetDirWrite();                        // DCF77 debug LED	
	}
	
	static void Update () {
/************************************************
	returns _pulse       @14.745600 MHz/1024 225 //  ONE_TICK 15.625ms 
	**************                               // ********************
												DCF77-LOW              //  100ms ~   6.4 ticks
												DCF77-HIGH             //  200ms ~  12.8 ticks
												
	returns _period       DCF77-Gap |1|          // 1800ms ~ 115.2 ticks
	***************                 |0|          // 1900ms ~ 121.6 ticks
	
 ***********************************************/
		static uint8_t _time;       //=0 (default) // counter      
		static uint8_t _pin ;       //=0 (default) // 0x00 | 0xff

		if( _time != 0xFF )                        // stop on 0xFF | 0x00..0xFF max.
				_time++;                               // count ticks

  	if( 1<<PA7 & //DCF77_SIG &                         // bit mask dcf77 input (PA7)
			(  PINA ^ _pin )) { //DCF77_PIN ^ dcf77_pin  ) ){             // true if different | pin changed
//		if( SIG::IsSet() ^ _pin ){                 // true if different | pin changed
		// ******************************************
		//
		// ******************************************
			_pin ^= 0xFF;                            // 0x00 | 0xff | 0x00 means pulse on
                                               //             | 0xff means pulse off
			if( _pin & 1<<PA7 ) { //SIG::Number ){             // if finished | 0xff & PA7 
					_period = _time;                     // store ticks of period
					_time   = 0;                         // reset | count next period
			}else{
					_pulse  = _time;                     // store ticks of pulse
			}
		}
	}
 
	static void decode( uint8_t pulse ) {
//***********************************************
// (c) peter dannegger | orig in timebase.c
//***********************************************
// uses _newtimedate.second as iterator !!!!
//***********************************************
		static uint8_t  parity = 0;
					 uint8_t  i;
					 uint8_t *d;

		i = _newtimedate.second - 21;              // second to index->BitNo[]
		if( i >= sizeof( BitNo )) return;          // only bit 21 ... 58

		parity ^= pulse;                           // "sum" parity

		i = LPM(&BitNo[i]);                        // load BitNo[] value
		
		if( i == 0xFF ){                           // test parity
			if( parity ) _error = 1;
			parity = 0;
			return;
		}
	
		d = &_newtimedate.minute + (i >> 4);       // bit ADDRESS + offset
	//*********************************************
	// indirect manipulation 
	// of struct _newtimedatef !!!!!
	//*********************************************
		i &= 0x0F;                                 // remove high nibble
		if( i == 0 ) *d = 0;                       // clear all, if lsb
		if( pulse  ) *d += LPM(&BitWeight[i]);     // add bits to digits
	}                                            // ********************

public:
	static void scan( ) {                        //  main loop
/************************************************
	dcf77_pulse          @14.745600 MHz/1024 225 //  ONE_TICK 15.625ms 
	********************                         // ********************
												DCF77-LOW              //  100ms ~   6.4 ticks
												DCF77-HIGH             //  200ms ~  12.8 ticks
												
	dcf77_period					DCF77-Gap |1|          // 1800ms ~ 115.2 ticks
	************                    |0|          // 1900ms ~ 121.6 ticks
	
 ***********************************************/
		if( _pulse ){
	//**************************************************************
			if     ( _pulse >  3 && _pulse <  9 ) decode( 0 );
			else if( _pulse > 10 && _pulse < 15 ) decode( 1 );
					 else                            _error = 1;
			_pulse = 0;
		}

		if( _period ) {
	//*********************************************
	//	synchronize 
	//	store data in _timedatef
	//*********************************************
			if( _newtimedate.second < 60 ) 
					_newtimedate.second++;               // count sec's
				
				if( _period > 100 
				 && _period < 140 ) {                  // 120..140 
			//*****************************************
					if( _error == 0 
						&& _newtimedate.second == 59 ) {
				//***************************************
					 _synchronize = 0xFF;                //
						TimeBase::sync_sec();              // reload timer0
				//*******************************************************************
						cClock<Display,TimeBase>::_timedate.second = 0;
						cClock<Display,TimeBase>::_timedate.minute = _newtimedate.minute;
						cClock<Display,TimeBase>::_timedate.hour   = _newtimedate.hour;
						cClock<Display,TimeBase>::_timedate.wday   = _newtimedate.wday;
						cClock<Display,TimeBase>::_timedate.day    = _newtimedate.day;
						cClock<Display,TimeBase>::_timedate.month  = _newtimedate.month;
						cClock<Display,TimeBase>::_timedate.year   = _newtimedate.year;
				//********************************************************************
				}
				_newtimedate.second = 0;               // reset
			 _error = 0;
			}
			else                                     // <110 | >130
				if( _period < 60 
					||_period > 70 ) _error = 1;
		//*******************************************
			_period = 0;
		}
	}
};

//____________________________________________________________________________
} //.Mcucpp
#endif //._DCF77_