/**************************************************************************************
** DCF77 Clock
** Empfaenger = Conrad DCF77 Modul
** 1. das positive Signal ist am INT0 Pin angeschlossen
** 2. alle 10msek muss per Interrupt timer2_signal aufgerufen werden (main.c)
**
** Auswertung des Timer2 in main.c
** Damit Auswertung der Pulsbreite usw.
**
** 24.04.2009 li Uhr soweit OK
** 26.04.2009 li Sonntag = 7
** 29.04.2009 li DCF77 LED ein/aus
** 20.05.2009 li Ziel: Nur jede Stunde das Zeitsignal auswerten
** 24.05.2009 li Zeitauswertung: Neue Minute erst bei Sekunde 0
** 21.07.2009 li wegen allgemeiner Verwendung, timer2 int auf 10msek
** 04.09.2009 li t2_o_cnt Problem, 100/200 mSek Erkennung funst nicht
** 16.10.2009 li timer2 auf compare match int umgestellt
** 02.03.2010 li Sekunden signal von DCF77 nur wenn parity ok
** 03.03.2010 li weitere Verbesserung wenn DCF77 Signal Stoerung hat
** 16.03.2010 li Anpassung an Atmega168
** 21.12.2010 li beim Ausfall dcf77 Sender Probleme
** 22.12.2010 li updates
** 28.01.2011 li korrekturen
** 31.01.2011 li 10msek Timer verlagert
** 01.02.2011 li #ifdef C_SONNEN  3628Bytes mehr
** 08.02.2011 li bis 12Uhr, SA hh:mm U hh:mm  Aufgang Untergang heute,
**               dann SU hh:mm A hh:mm  Untergang heute, Aufgang morgen
** 07.05.2011 li C_GEOVAR: Sonnenzeiten über variablen in clock_s berechnen.
**               Vergrößert das clock Programm um ca. 172 Bytes.    
*/
#include <math.h>
#include "basis.h"
#include "clock.h"
#include "lcd.h"
                
#ifdef DCF_FLASH2 
                   // 01234567890123456789      06.05.2011
char zeile01[ 21 ] = "  Son dd.mm.20jj    " ;   // jahr = xx
char zeile02[ 21 ] = "  MEZ  hh:mm:ss  X  " ;   // 20.05.09 an pos15 korr.
char zeile03[ 21 ] = " SA hh:mm  SU hh:mm " ;   // 06.05.2011
                   // sleep_over 0     1     2     3
unsigned char zeile215[5] = { 0xD1, 0xD2, 0xD3, 0xD4};
#else
                   /* 0123456789012345 */
char zeile01[ 17 ] = "Son dd.mm.20jj  " ;   // jahr = xx
char zeile02[ 17 ] = "MEZ  hh:mm:ss  X" ;   // 20.05.09 an pos15 korr.
                   // sleep_over 0     1     2     3
unsigned char zeile215[5] = {  'O',  'o', 0xA1, 0xA5 };
#endif

extern char zeile11[17];

                                  // Display Parameter
extern volatile S_LCD_ANZ lcdanz_s;

                                  // Timer2 +++++++++++++++++++++++++++++++++
unsigned char t2_o_cnt;           // +1 alle 10msek timer2 compare match
                                        // 100 = 1 Sekunde
volatile unsigned char gp_cnt_high = 0;
volatile unsigned char gp_cnt_low  = 0;
volatile unsigned char t2_gp_cnt = 0;      // 10 millisekunden Counter

                        // jan feb mar apr mai jun jul aug sep okt nov dez
unsigned char mtab[12]  = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };


#ifdef DCF_RECEIVER

#undef DCF_FLASH_LED
#undef DCF_FLASH_HIGH             // 1 dann LED ON 

#ifdef DCF_FLASH
#define DCF_FLASH_LED

#ifdef A_MASTER
#define LRX_CNTL_DDR  DDRD        // DCF77 Signal LED
#define LRX_CNTL_PORT PORTD       // DCF77 Signal LED
#define LRX_CNTL_BIT  BIT3        // DCF77 signal LED
#endif

#ifdef A_MASTER_TEST
#define LRX_CNTL_DDR  DDRD        // DCF77 Signal LED
#define LRX_CNTL_PORT PORTD       // DCF77 Signal LED
#define LRX_CNTL_BIT  BIT3        // DCF77 signal LED
#endif

#ifdef A_KAFFEE
#define LRX_CNTL_DDR  DDRD        // DCF77 Signal LED
#define LRX_CNTL_PORT PORTD       // DCF77 Signal LED
#define LRX_CNTL_BIT  BIT3        // DCF77 signal LED
#endif

#ifdef A_KAFFEE_P
#define LRX_CNTL_DDR  DDRD        // DCF77 Signal LED
#define LRX_CNTL_PORT PORTD       // DCF77 Signal LED
#define LRX_CNTL_BIT  BIT3        // DCF77 signal LED
#endif

#ifdef A_DCF77                    // DCF77 / Frequ Messer
#define LRX_CNTL_DDR  DDRC        // DCF77 Signal LED
#define LRX_CNTL_PORT PORTC       // DCF77 Signal LED
#define LRX_CNTL_BIT  BIT5        // DCF77 signal LED
#endif

#endif    // ifdef DCF_FLASH


#ifdef DCF_FLASH2                 // DCF77 Uhr    
#define DCF_FLASH_LED
#define DCF_FLASH_HIGH  
#define LRX_CNTL_DDR  DDRC        // DCF77 Signal LED
#define LRX_CNTL_PORT PORTC       // DCF77 Signal LED
#define LRX_CNTL_BIT  BIT4        // DCF77 signal LED
#endif 

#ifdef DCF_FLASH_LED
unsigned char dcf_flash  = 0;  // sekunden LED flash
#endif

                                  // 4 Bitbuffer a 16Bits
unsigned int volatile rxbuf[4] = {0,0,0,0};
                                  // Bitbuffer SaveArea
unsigned int volatile sxbuf0 = 0;
unsigned int volatile sxbuf1 = 0;
unsigned int volatile sxbuf2 = 0;
unsigned int volatile sxbuf3 = 0;

unsigned char  volatile rx_bit_counter = 0;

unsigned char last_flag = 0;      // flag einen DCF77-Takt vorher

unsigned char check_p = 0;        // parity flags
#define CHECK_P1    0x01          // wenn PARITY P1 ok
#define CHECK_P2    0x02          // wenn PARITY P2 ok
#define CHECK_P3    0x04          // wenn PARITY P3 ok
#define START_BIT   0x08          // Time Start Bit

#endif                   // ende DCF_RECEIVER

#ifdef TIM2_KORR
   unsinn char t2_korr = 1;        // jeder 8. interrupt soll einen Takt laenger dauern
#endif

S_CLOCK volatile clock_s;          // allgemeine clock struktur

void timer2_init(void);
void trace_Zeit( unsigned char merker);
void upd_Sekunde (void);
void conv_date( void );
void conv_zeit( void );

#ifdef C_SONNEN
float JulianischesDatum( int Jahr,
                         unsigned char Monat,
                         unsigned char Tag,
                         unsigned char Stunde,
                         unsigned char Minuten,
                         unsigned char Sekunden );
float InPi(float x);
float eps(float T);
float BerechneZeitgleichung(float *DK, float T);
unsigned char computesommer( unsigned char tag, unsigned char monat, unsigned char wtag );
void compute_s0(void);
void compute_s1(void);


#define PI2  6.283185307179586476925286766559
#define PI   3.1415926535897932384626433832795
#define RAD  0.017453292519943295769236907684886

#ifndef C_GEOVAR
               // Ort in Ffm
#define GEOLAENGE  8.64385      //  8°38'37,86"
#define GEOBREITE 50.08736      // 50°05'14,54"
#endif

float Aufgang;
float Untergang;


/*******************************************************
** Input
** Jahr:  vierstellige Zahl z.B. 2011
** Monat: 1-12
** Tag:   1-31 je nach Monat
*/
void compute_sonnenzeiten( int Jahr, unsigned char Monat, unsigned char Tag , unsigned char wtag);
#endif


/**************************************************************************************
** ####################################################
** diese Abfrage muss in die main loop eingebaut werden
** ####################################################
**
** alle 10msek: clock_s.tim2ovf
*/
void timer2_signal(void)
{
   t2_o_cnt += clock_s.tim2ovf;  // anzahl merken   
    
   if ( t2_gp_cnt )
      t2_gp_cnt += clock_s.tim2ovf;
      
   clock_s.tim2ovf = 0;          // reset flag
   if ( t2_o_cnt >= 100 )        // 100  = 1 Sekunde
   {
      t2_o_cnt = 0 ;             // reset t2 overflow counter
#ifdef DCF_RECEIVER

      if ( clock_s.dcf_flag & DCF_RX )   // DCF77 signal da gewesen
      {
         if ( rx_bit_counter == 59 )
         {
            if ( check_p == (CHECK_P1+CHECK_P2+CHECK_P3+START_BIT) )   // Alles OK?
            {
               clock_s.ss = 59;
               clock_s.dcf_flag |= DCF_SYNC + DCF_SYNC2 + DCF_UPD ;
               sxbuf0 = rxbuf[0];        // save Bitbuffer
               sxbuf1 = rxbuf[1];
               sxbuf2 = rxbuf[2];
               sxbuf3 = rxbuf[3];
            }
         }
         else
         {
            clock_s.dcf_flag &= ~DCF_SYNC ;      // reset sync
         }
      }
      else
      {
         clock_s.dcf_flag &= ~DCF_SYNC ;  // reset sync
         if ( clock_s.Sleep_Sw )      // Zeitsignal nur alle Stunde auswerten ?
         {
            if ( clock_s.sleep >= 900 )  // 1/4 h
            {
               clock_s.sleep = 0;
               clock_s.sleep_over++;
            }
            clock_s.sleep++;          // wartezeit in Sec.
         }
      }
#endif
      display_Zeit( 0x53 );
      clock_s.display_time = 1; // Sekunden display am Start Pulse
      upd_Sekunde();
   }
}



/**************************************************************************************
** Hex-Display des 64 Bit Buffers sowie weitere Werte
*/
void trace_Zeit( unsigned char merker)
{
#ifdef DCF_RECEIVER

   edit_hex( 4, rxbuf[3], zeile11 );
   edit_hex( 4, rxbuf[2], zeile11+4 );
   edit_hex( 4, rxbuf[1], zeile11+8 );
   edit_hex( 4, rxbuf[0], zeile11+12 );

   if ( clock_s.display_flag & 0x01 )     // Zeile 1
   {
#ifdef A_MASTER_TEST
      set_cursor( 0, 3);
      lcd_string( zeile11 );
#else
      set_cursor( 0, 1);
      lcd_string( zeile11 );
#endif          // A_MASTER_TEST      
}

                // 222222222222222222222222222222222222222
   edit_hex( 2, gp_cnt_high, zeile11 );
   zeile11[2] = ' ';
   edit_hex( 2, gp_cnt_low, zeile11+3 );
   zeile11[5] = ' ';
   edit99( rx_bit_counter, zeile11+6, 2 );
   zeile11[8] = ' ';
   edit_hex( 2, clock_s.dcf_flag, zeile11+9 );
   zeile11[11] = ' ';
   edit99( merker, zeile11+12, 2 );     // merker
   zeile11[14] = ' ';
   zeile11[15] = ' ';

   if ( clock_s.display_flag & 0x02 )     // 2. Zeile
   {
#ifdef A_MASTER_TEST
      set_cursor( 0, 4);
      lcd_string( zeile11 );
#else       // A_MASTER_TEST
      set_cursor( 0, 2);
      lcd_string( zeile11 );
#endif     // A_MASTER_TEST 
   }
#endif     // DCF_RECEIVER
}



/**************************************************************************************
** Zeit anzeigen
*/
void display_Zeit( unsigned char todo )
{
#ifdef DCF_RECEIVER
   unsigned int xx;
   unsigned char var;
#ifdef DCF_FLASH2
   unsigned char sh;
#else   // DCF_FLASH2
   unsigned char sh,v;
#endif  // DCF_FLASH2
#else   // DCF_RECEIVER
   unsigned char sh,v;
#endif  // v

   sh = (todo & 0xF0) >> 4;
   todo  &=  0x0F;

   clock_s.display_time = 0;  // reset display switch

   if ( clock_s.time_trace )
   {
      trace_Zeit( todo );     // trace bitbuffer etc.
#ifndef A_MASTER_TEST
      return;
#endif // A_MASTER_TEST
   }
#ifdef DCF_RECEIVER
/*-------------------------------------------------------------------------------
    Bits im Bitbuffer

    6            5           4            3           2            1
 3210 9876 5432 1098 7654 3210 9876 5432 1098 7654 3210 9876 5432 1098 7654 3210
 .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... ....
 3333 3333 3333 3333 2222 2222 2222 2222 1111 1111 1111 1111 0000 0000 0000 0000
      .Pjj jjjj jjMM MMMw wwdd dddd Phhh hhhP mmmm mmmS AMZ. .... .... .... ..M0
       3                            2       1         .  01 = MESZ
                                                      .  10 = MEZ
                                                      S = immer 1
--------------------------------------------------------------------------------*/
   if ( todo == 3 && clock_s.dcf_flag & DCF_UPD && clock_s.ss == 0 )
   {                                    // Bits filtern und nach binary umsetzen
      clock_s.dcf_flag &= ~DCF_UPD;     // reset flag

      clock_s.sleep = 0;
      clock_s.sleep_over = 0;

      xx = sxbuf1 & 0x0006 ;
      xx >>= 1 ;
      clock_s.dmz = (unsigned char)xx;

      xx = sxbuf1 & 0xE000 ;
      xx >>= 13 ;
      xx += (sxbuf2 & 0x0007) << 3 ;
      var = (unsigned char)xx;
      var = ((var >> 4) * 10) + (var & 0x0F); // binary Umwandlung
      clock_s.dhh = var;

      xx = sxbuf1 & 0x0FE0 ;
      xx >>= 5;
      var = (unsigned char)xx;
      var = ((var >> 4 )* 10) + (var & 0x0F);   // binary Umwandlung
      clock_s.dmm = var;

      xx = sxbuf2 & 0x1C00 ;
      var = (unsigned char)(xx >> 10 );         // ist binary
      clock_s.wday = var;

      xx = sxbuf2 & 0x03F0 ;
      xx >>= 4;
      var = (unsigned char)xx;
      var = ((var>>4) * 10) + (var & 0x0F);     // binary Umwandlung
      clock_s.day = var;

      xx = sxbuf2 & 0xE000 ;
      xx >>= 13;
      xx += (sxbuf3 & 0x0003) << 3 ;
      var = (unsigned char)xx;
      var = ((var>>4) * 10) + (var & 0x0F);     // binary Umwandlung
      clock_s.mon = var;

      xx = sxbuf3 & 0x03FC;
      xx >>= 2;
      var = (unsigned char)xx;
      var = ((var>>4)* 10) + (var & 0x0F);     // binary Umwandlung
      clock_s.year = var;
   }
#endif              // DCF_RECEIVER

   conv_date();
   clock_s.dcf_flag |= UPD_ZEILE1;
   clock_s.gflag = 0;

   // edit_hex( 2, clock_s.dcf_flag, zeile01+14 );
   conv_zeit();
#ifdef DCF_FLASH2
                                             // Status Zeichen zeile2 Pos 17
   if ( clock_s.dcf_flag & DCF_SYNC )
      zeile02[17] = 0xD0 ;        // Spezial Rechteck
   else if ( clock_s.dcf_flag & DCF_RX )
      zeile02[17] = 'S';          // Auswerten
   else
   {
      if ( clock_s.Sleep_Sw && clock_s.dcf_flag & DCF_SYNC2 )
         zeile02[17] = zeile215[ clock_s.sleep_over ];
      else
         zeile02[17] = 'X';       // Zeitsignal fehlt
   }
#else   // DCF_FLASH2
                                             // Status Zeichen zeile2 Pos 15
   if ( clock_s.dcf_flag & DCF_SYNC )
      zeile02[15] = 0xDB ;        // Spezial Rechteck
   else if ( clock_s.dcf_flag & DCF_RX )
      zeile02[15] = 'S';          // Auswerten
   else
   {
      if ( clock_s.Sleep_Sw && clock_s.dcf_flag & DCF_SYNC2 )
         zeile02[15] = zeile215[ clock_s.sleep_over ];
      else
         zeile02[15] = 'X';       // Zeitsignal fehlt
   }
#endif   // DCF_FLASH2
   if ( clock_s.dcf_flag & UPD_ZEILE1 && clock_s.display_flag & 0x01 )
   {
#ifdef A_TEST168
      set_cursor( 0, 3);
      lcd_string( zeile01 );
#endif  // A_TEST168    

#ifdef C_SONNEN

#ifndef DCF_FLASH2 
      v = clock_s.ss / 10;
      if ( v == 1 || v == 3 || v == 5 )
      {
         zeile01[0] = 'S';
         zeile01[1] = 'A';
         zeile01[2] = ' ';
         zeile01[5] = ':';
         zeile01[8] = ' ';
         zeile01[9] = 'U';
         zeile01[10] = ' ';
         zeile01[13] = ':';
         if ( clock_s.dhh < 12 )
         {
            if ( (clock_s.gflag & 0x01) == 0 )
               compute_s0();
            edit99( clock_s.sa / 60, zeile01+3, 2 );
            edit99( clock_s.sa % 60, zeile01+6, 2 );
            edit99( clock_s.su / 60, zeile01+11, 2 );
            edit99( clock_s.su % 60, zeile01+14, 2 );
         }
         else
         {
            if ( (clock_s.gflag & 0x01) == 0 )
               compute_s0();
            if ( (clock_s.gflag & 0x02) == 0 )
               compute_s1();   
            zeile01[1] = 'U';
            zeile01[9] = 'A';
            edit99( clock_s.su / 60, zeile01+3, 2 );
            edit99( clock_s.su % 60, zeile01+6, 2 );
            edit99( clock_s.sa1 / 60, zeile01+11, 2 );
            edit99( clock_s.sa1 % 60, zeile01+14, 2 );
         }
      }
#endif        // DCF_FLASH2
#endif        // C_SONNEN
      set_cursor( 0, 1);
      lcd_string( zeile01 );

      if ( clock_s.dmm < 55 && clock_s.Sleep_Sw && clock_s.dcf_flag & DCF_SYNC2 )
      {
         stopp_clock();           // stopp clock
      }
      clock_s.dcf_flag &= ~UPD_ZEILE1 ;
   }
   if ( clock_s.display_flag & 0x02 )
   {
      set_cursor( 0, 2);
      lcd_string( zeile02 );
   }

#ifdef C_SONNEN      
#ifdef DCF_FLASH2
   if ( clock_s.display_flag & 0x04 )
   {  
      zeile03[2]  = 'A';
      zeile03[12] = 'U';
      
      if ( clock_s.dhh < 12 )
      {
         if ( (clock_s.gflag & 0x01) == 0 )
            compute_s0();
         
         edit99( clock_s.sa / 60, zeile03+4, 2 );
         edit99( clock_s.sa % 60, zeile03+7, 2 );
         edit99( clock_s.su / 60, zeile03+14, 2 );
         edit99( clock_s.su % 60, zeile03+17, 2 );
      }
      else
      {
         if ( (clock_s.gflag & 0x01) == 0 )
            compute_s0();
         if ( (clock_s.gflag & 0x02) == 0 )
            compute_s1();
            
         zeile03[2] = 'U';
         zeile03[12] = 'A';
         edit99( clock_s.su / 60, zeile03+4, 2 );
         edit99( clock_s.su % 60, zeile03+7, 2 );
         edit99( clock_s.sa1 / 60, zeile03+14, 2 );
         edit99( clock_s.sa1 % 60, zeile03+17, 2 );
      }
      set_cursor( 0, 3);      
      lcd_string( zeile03 );
   }
#endif  // DCF_FLASH2 
#endif  //  C_SONNEN
}



/**************************************************************************************
** default: Don Don
**          M   Mon
**          S   Son
**           ie Die
**          Mit
**          Fre
**          Sam
*/
void conv_date( void )
{
#ifdef DCF_FLASH2
   zeile01[0] = ' ';
	zeile01[1] = ' ';
   zeile01[2] = 'D';
   zeile01[3] = 'o';
   zeile01[4] = 'n';
   zeile01[5] = ' ';
   if ( clock_s.wday == 1 )
      zeile01[2] = 'M';    // Mon
   else if ( clock_s.wday == 7 )
      zeile01[2] = 'S';    // Son
   else if ( clock_s.wday == 2 )
   {
      zeile01[3] = 'i';    // Die
      zeile01[4] = 'e';
   }
   else if ( clock_s.wday == 3 )
   {
      zeile01[2] = 'M';
      zeile01[3] = 'i';
      zeile01[4] = 't';
   }
   else if ( clock_s.wday == 5 )
   {
      zeile01[2] = 'F';
      zeile01[3] = 'r';
      zeile01[4] = 'e';
   }
   else if ( clock_s.wday == 6 )
   {
      zeile01[2] = 'S';
      zeile01[3] = 'a';
      zeile01[4] = 'm';
   }
   edit99( clock_s.day,  zeile01+6, 2 );
   zeile01[8] = '.';
   edit99( clock_s.mon,  zeile01+9, 2 );
   zeile01[11] = '.';
   zeile01[12] = '2';
   zeile01[13] = '0';
   edit99( clock_s.year, zeile01+14, 2 );
   zeile01[16] = ' ';
   zeile01[17] = ' ';
	zeile01[18] = ' ';
	zeile01[19] = ' ';	
#else   //  DCF_FLASH2   
                      // Wochentag
   zeile01[0] = 'D';
   zeile01[1] = 'o';
   zeile01[2] = 'n';
   zeile01[3] = ' ';
   if ( clock_s.wday == 1 )
      zeile01[0] = 'M';    // Mon
   else if ( clock_s.wday == 7 )
      zeile01[0] = 'S';    // Son
   else if ( clock_s.wday == 2 )
   {
      zeile01[1] = 'i';    // Die
      zeile01[2] = 'e';
   }
   else if ( clock_s.wday == 3 )
   {
      zeile01[0] = 'M';
      zeile01[1] = 'i';
      zeile01[2] = 't';
   }
   else if ( clock_s.wday == 5 )
   {
      zeile01[0] = 'F';
      zeile01[1] = 'r';
      zeile01[2] = 'e';
   }
   else if ( clock_s.wday == 6 )
   {
      zeile01[0] = 'S';
      zeile01[1] = 'a';
      zeile01[2] = 'm';
   }
   edit99( clock_s.day,  zeile01+4, 2 );
   zeile01[6] = '.';
   edit99( clock_s.mon,  zeile01+7, 2 );
   zeile01[9] = '.';
   zeile01[10] = '2';
   zeile01[11] = '0';
   edit99( clock_s.year, zeile01+12, 2 );
   zeile01[14] = ' ';
   zeile01[15] = ' ';
#endif   //  DCF_FLASH2
}



/**************************************************************************************
** Stunde aufbereiten
** Minute aufbereiten, wenn 58 Minute dann gegebenenfalls DCF77 sync anfordern
** und Sekunde
** MESZ oder MEZ anzeigen
*/
void conv_zeit( void )
{
#ifdef DCF_FLASH2                           // --------------------------------
   edit99( clock_s.dhh, zeile02+7, 2 );
   zeile02[9] = ':';
      // kein int0 zugelassen = stopp clock war da
#ifdef DCF_RECEIVER
#if defined(__AVR_ATmega168__)
   if ( clock_s.Sleep_Sw && !(EIMSK & (1<<INT0)) && clock_s.dmm > 57 )
#else   // __AVR_ATmega168__
   if ( clock_s.Sleep_Sw && !(GICR & (1<<INT0)) && clock_s.dmm > 57 )
#endif  // __AVR_ATmega168_
      start_clock();
#endif // DCF_RECEIVER

   edit99( clock_s.dmm, zeile02+10, 2 );
   zeile02[12] = ':';

   edit99( clock_s.ss, zeile02+13, 2 );
   zeile02[15] = ' ';

   zeile02[2] = 'M';
   zeile02[3] = 'E';

   if ( clock_s.dmz == 0x01 )        // .... ..01
   {
      zeile02[4] = 'S';
      zeile02[5] = 'Z';
   }
   else if ( clock_s.dmz == 0x02 )   // .... ..10
   {
      zeile02[4] = 'Z';
      zeile02[5] = ' ';
   }
   else
   {
      zeile02[4] = '?';
      zeile02[5] = '?';
   }
#else  // DCF_FLASH2                           ---------------------- 
   edit99( clock_s.dhh, zeile02+5, 2 );
   zeile02[7] = ':';
      // kein int0 zugelassen = stopp clock war da
#ifdef DCF_RECEIVER
#if defined(__AVR_ATmega168__)
   if ( clock_s.Sleep_Sw && !(EIMSK & (1<<INT0)) && clock_s.dmm > 57 )
#else
   if ( clock_s.Sleep_Sw && !(GICR & (1<<INT0)) && clock_s.dmm > 57 )
#endif  // __AVR_ATmega168_
      start_clock();
#endif // DCF_RECEIVER

   edit99( clock_s.dmm, zeile02+8, 2 );
   zeile02[10] = ':';

   edit99( clock_s.ss, zeile02+11, 2 );
   zeile02[13] = ' ';

   zeile02[0] = 'M';
   zeile02[1] = 'E';

   if ( clock_s.dmz == 0x01 )        // .... ..01
   {
      zeile02[2] = 'S';
      zeile02[3] = 'Z';
   }
   else if ( clock_s.dmz == 0x02 )   // .... ..10
   {
      zeile02[2] = 'Z';
      zeile02[3] = ' ';
   }
   else
   {
      zeile02[2] = '?';
      zeile02[3] = '?';
   }
#endif   // DCF_FLASH2                           -------------------
}



/**************************************************************************************
** DCF77 Modul empfaengt Traeger
** positive Impulse werden ausgewertet
** Interrupt:  erst ansteigende Flanke, dann abfallende Flanke
*/
ISR( INT0_vect )
{
#ifdef DCF_RECEIVER
   register unsigned char h,rxbit;
   register unsigned int value;
                                 // Pulsweite bestimmen
#if defined(__AVR_ATmega168__)
   if ( (EICRA & INT0_RISING_EDGE) == INT0_RISING_EDGE)
   {
      EICRA &= ~BIT0;             // clear BIT0 = INT0_FALLING_EDGE
#else
   if ( (MCUCR & INT0_RISING_EDGE) == INT0_RISING_EDGE)
   {
      MCUCR &= ~BIT0;             // clear BIT0 = INT0_FALLING_EDGE
#endif

      gp_cnt_low = t2_gp_cnt;

#ifdef DCF_FLASH_LED
      if ( dcf_flash & BIT0 )     // 29.04.2009
#ifdef DCF_FLASH_HIGH
         LRX_CNTL_PORT |= LRX_CNTL_BIT;    // LED ein (fun) 
#else		
         LRX_CNTL_PORT &= ~LRX_CNTL_BIT;   // LED ein (fun)
#endif			
#endif

      if ( clock_s.dcf_flag & DCF_RX) ; // dcf77 Signal Suche
      {
         if ( gp_cnt_low > 165 )     // > 1650 msek = neuer Cyclus
         {
            rx_bit_counter = 0;
            clock_s.ss = 0;
            check_p = 0;
            rxbuf[0] = 0;
            rxbuf[1] = 0;
            rxbuf[2] = 0;
            rxbuf[3] = 0;
            t2_o_cnt = 95;      // Sekunde Syncronisieren
         }
      }
      t2_gp_cnt = 1;
   }
   else
   {
                                  // Fallende Flanke
#if defined(__AVR_ATmega168__)
      EICRA |= INT0_RISING_EDGE;  // 0x03 = beide Bits
#else
      MCUCR |= INT0_RISING_EDGE;  // 0x03 = beide Bits
#endif

#ifdef DCF_FLASH_LED
#ifdef DCF_FLASH_HIGH
      LRX_CNTL_PORT &= ~LRX_CNTL_BIT; // LED aus (fun)
#else
      LRX_CNTL_PORT |= LRX_CNTL_BIT; // LED aus (fun)
#endif
#endif
      gp_cnt_high = t2_gp_cnt;

      if ( gp_cnt_high >= 9 )        // minimal 80 msek Impuls
      {
         rxbit = 0;

         if ( (clock_s.dcf_flag & DCF_RX) == 0 ) // DCF Suche noch nicht da ??
         {
            clock_s.dcf_flag |= DCF_RX;     // setze DCF77 decodieren
            rx_bit_counter = 0;
            check_p = 0;
            rxbuf[0] = 0;
            rxbuf[1] = 0;
            rxbuf[2] = 0;
            rxbuf[3] = 0;
         }
         last_flag = clock_s.dcf_flag;      // merke letztes parity flag

         rxbit = 0;
         if ( gp_cnt_high >= 18 )           // 180msec => 1 Impuls erkannt
         {
            rxbit = 1;
            h = (rx_bit_counter >> 4) & 0x03;       // high
            value = (1 << (rx_bit_counter & 0x0F)); // wert
            rxbuf[h] |= value;                      // 1 im rxbuffer setzen
            clock_s.dcf_flag ^= PARITY ;            // toggle parity bit
         }
                                             // Zeitinfo, Paritaet ok ?
         if ( rx_bit_counter == 20 )
         {
            if ( rxbit)                      // merke Zeit Start Bit
               check_p |= START_BIT ;
            clock_s.dcf_flag &= ~PARITY ;    // clear parity Bit
         }
         else if ( rx_bit_counter == 28 )
         {
            clock_s.dcf_flag &= ~PARITY ;
            if ( rxbit == (last_flag & PARITY) )
               check_p |= CHECK_P1;
         }
         else if ( rx_bit_counter == 35 )
         {
            clock_s.dcf_flag &= ~PARITY ;
            if ( rxbit == (last_flag & PARITY) )
               check_p |= CHECK_P2;
         }
         else if ( rx_bit_counter == 58 )
         {
            if ( rxbit == (last_flag & PARITY) )
               check_p |= CHECK_P3;
         }
                                  // Naechster Interrupt bei ansteigender Flanke
         rx_bit_counter++;
         rx_bit_counter &= 0x3f;         // 0-63 zulassen
      }
      t2_gp_cnt = 1;             // start gap messung
   }
#endif
}



/**************************************************************************************
** sekunden update, wenn kein DCF_SYNC. dann minute ++ usw
** 08.02.2011 li mtab benutzen
*/
void upd_Sekunde (void)
{
   clock_s.ss++;
   if (clock_s.ss == 60)
   {
      clock_s.ss = 0;
      clock_s.dmm++;
      if (clock_s.dmm == 60)
      {
         clock_s.dmm = 0;
         clock_s.dhh++;
         if (clock_s.dhh == 24)
         {
            clock_s.dhh = 0;
            clock_s.day++;
            clock_s.wday++;
            if ( clock_s.wday == 8 )
               clock_s.wday = 1;
            if ( clock_s.year % 4 == 0 && clock_s.year > 0 )
               mtab[1] = 29;
            else
               mtab[1] = 28;
            if ( clock_s.day > mtab[clock_s.mon-1] )
            {
               clock_s.day = 1;
               clock_s.mon += 1;
               if ( clock_s.mon > 12 )
               {
                  clock_s.mon = 1;
                  clock_s.year += 1;
               }
            }
         }
      }
   }
}



/**************************************************************************************
** Diese Routine start Timer2
**
** 26.1.2011 li sleep_merker eingebaut
*/
void start_clock( void )
{
#ifdef DCF_RECEIVER

#if defined(__AVR_ATmega168__)
   EIMSK |= (1<<INT0);
   EICRA  |= INT0_RISING_EDGE;       // 0x03 beide Bits
#else
   GICR |= (1<<INT0);                // int0 interrupt zulassen
   MCUCR |= INT0_RISING_EDGE;        // 0x03 beide Bits
#endif  // AVR_ATmega168

   DDRD  &= ~BIT2;                   // (INT0) PD2 als Input
   PORTD &= ~BIT2;                   // Input ohne internen Pullup Widerstand
   rx_bit_counter = 0;

#endif // DCF_RECEIVER

   clock_s.sleep = 0;
   clock_s.sleep_over = 0;
   t2_gp_cnt = 0;

#ifdef DCF_FLASH_LED
   LRX_CNTL_DDR |= LRX_CNTL_BIT ;    // BIT5 PortC (pin28) auf Output
                                     // jeweils 1 wenn DCF77 Signal erkannt.
#ifdef DCF_FLASH_HIGH
   LRX_CNTL_PORT &= ~LRX_CNTL_BIT;   // Ausgang auf 0 => LED aus.
#else												 
   LRX_CNTL_PORT |= LRX_CNTL_BIT;    // Ausgang auf 1 => LED aus.
#endif
#endif
}



/**************************************************************************************
** Diese Routine stoppt die INT0 Unterbrechungen
*/
void stopp_clock(void)
{
#if defined(__AVR_ATmega168__)
   EIMSK &= ~(1<<INT0);               // INT0 Interrupt ausschalten
#else
   GICR  &= ~(1<<INT0);               // INT0 Interrupt ausschalten
#endif
#ifdef DCF_FLASH_LED
#ifdef DCF_FLASH_HIGH
   LRX_CNTL_PORT &= ~LRX_CNTL_BIT;   // Ausgang auf 0 => LED aus.
#else
   LRX_CNTL_PORT |= LRX_CNTL_BIT;    // Ausgang auf 1 => LED aus.
#endif
#endif
   clock_s.dcf_flag &= ~( DCF_RX + DCF_SYNC );
   t2_gp_cnt = 0;
}



#ifdef C_SONNEN
/*****************************************************************************
** Sonnenaufgang und Sonnenuntergang berechnen
** genauere Formel 2005, siehe http://lexikon.astronomie.info/zeitgleichung
**
** 03.02.2011 li Berechnung dauert bei 6,144MHz ca. 6,0 bis 6,8 msek
** 11.02.2011 li Der Avr-GCC benutzt nur float. Die Abweichung zu double wurde in
**               einem PC-Programm simuliert: Meistens die gleichen Zeiten, manchmal
**               +-1 Minute Abweichung fuer einen Tag.
** 07.05.2011 li Länge und Breite mit 4 Stellen hinter dem Komma aus clock_s wenn C_GEOVAR
*/
void compute_sonnenzeiten( int Jahr, unsigned char Monat, unsigned char Tag, unsigned char wtag )
{
   float JD2000 = 2451545.0;
   float JD, T, DK, h, B;
#ifdef C_GEOVAR
   float L;
#endif
   float Zeitgleichung;
   float Zeitdifferenz;
   float AufgangOrtszeit;
   float UntergangOrtszeit;
   unsigned char summertime;

   JD = JulianischesDatum( Jahr, Monat, Tag, 12, 0, 0);

   T = (JD - JD2000) / 36525.0;
   h = -50.0/60.0 * RAD;          // -50 Minuten Horizont

#ifdef C_GEOVAR
   B = clock_s.geobre / 10000.0;  //
   B *= RAD;                      // geographische Breite
#else
	B = GEOBREITE * RAD;                      // geographische Breite
#endif

   Zeitgleichung = BerechneZeitgleichung( &DK, T);
   Zeitdifferenz = 12.0 * acos((sin(h) - sin(B) * sin(DK)) / (cos(B) * cos(DK))) / PI;
   AufgangOrtszeit = 12.0 - Zeitdifferenz - Zeitgleichung;
   UntergangOrtszeit = 12.0 + Zeitdifferenz - Zeitgleichung;

#ifdef C_GEOVAR   
	L = clock_s.geolen / 10000.0;  // geographische Länge 
	Aufgang = AufgangOrtszeit - ( L / 15.0 ) +  1.0;
   Untergang = UntergangOrtszeit - (L / 15.0) + 1.0;
#else
   Aufgang = AufgangOrtszeit - GEOLAENGE / 15.0  +  1.0;
   Untergang = UntergangOrtszeit - GEOLAENGE / 15.0 + 1.0;
#endif

   summertime = computesommer( Tag,  Monat, wtag );  // Sommerzeit gueltig

   if ( summertime )              // Sommerzeit ??
      Aufgang += 1.0;

   if (Aufgang < 0.0)
      Aufgang +=24.0;
   else if (Aufgang >= 24.0)
      Aufgang -= 24.0;

   if ( summertime )              // Sommerzeit ??
      Untergang += 1.0;

   if (Untergang < 0.0)
      Untergang += 24.0;
   else if (Untergang >= 24.0)
      Untergang -= 24.0;

   Aufgang   += 0.00499;          // Rundung
   Untergang += 0.00499;          // Rundung
}



/*********************************************************************
** Diese Berechnung wurde notwendig fuer die Zeiten des naechsten Tages, da
** DCF77 nur die aktuelle Sommerzeit / Winterzeit liefert.
**
** Input tag, monat, wtag: 1=Mo 2=Di 3=Mi 4=Do 5=Fr 6=Sa 7=So
** return 1 = Sommerzeit
*/
unsigned char computesommer( unsigned char tag, unsigned char monat, unsigned char wtag )
{
   unsigned char rc = 0;

   if ( wtag == 0 || monat < 3 || monat > 10 )
      return rc;

   if ( wtag == 8 )       // korrektur
      wtag = 1;
                          // so=7, mo=6 di=5 mi=4 do=3 fr=2 sa=1
   wtag = 7 - wtag;
   if ( wtag == 0 )
      wtag = 7;

   if ( monat == 3 )      // letzer Sonntag im Maerz = Start Sommerzeit
   {
      tag += wtag;
      if ( tag >= 31 )
         rc = 1;
   }
   else if (monat == 10)  // letzer Sonntag im Oktober = Ende Sommerzeit
   {
      rc = 1;
      tag += wtag;
      if ( tag >= 31 )
         rc = 0;
   }
   else
      rc = 1;

   return rc;
}




/*******************************************************************************
** Julianisches Datum  / Gregorianischer Kalender
*/
float JulianischesDatum( int Jahr,                       // 4 stellig
                         unsigned char Monat,            // 1-12
                         unsigned char Tag,              // 1 bis ..
                         unsigned char Stunde,
                         unsigned char Minuten,
                         unsigned char Sekunden )
{
   int Gregor, i;
   float rc;
   float var;

   if (Monat <= 2 )
   {
      Monat=Monat +12;
      Jahr = Jahr -1;
   }
   Gregor = (Jahr/400) - (Jahr/100) + (Jahr/4);  // Gregorianischer Kalender

   rc = 2400000.5 + 365.0 * Jahr - 679004.0 + Gregor ;
   var = 30.6001 * (Monat+1);
   i = (int)var;
   rc += var;
   rc += Tag + Stunde/24.0 + Minuten/1440.0 + Sekunden/86400.0;
   return rc;
}



/*******************************************************************************
** Utility
*/
float InPi(float x)
{
   int n = (int)(x / PI2);

   x = x - n * PI2;
   if ( x < 0)
      x += PI2;
   return x;
}



/*******************************************************************************
** Neigung der Erdachse
*/
float eps(float T)
{
   return RAD*(23.43929111 + (-46.8150*T - 0.00059*T*T + 0.001813*T*T*T)/3600.0);
}



/*******************************************************************************
** Zeitgleichung
*/
float BerechneZeitgleichung(float *DK, float T)
{
   float RA_Mittel, M, L, e, RA, dRA;

   RA_Mittel = 18.71506921 + 2400.0513369 * T + (2.5862e-5 - 1.72e-9 * T) * T * T;
   M  = InPi(PI2 * (0.993133 + 99.997361 * T));
   L  = InPi(PI2 * ( 0.7859453 + M / PI2 + (6893.0 * sin(M) + 72.0 * sin(2.0 * M) + 6191.2 * T) / 1296.0e3));
   e = eps(T);

   RA = atan( tan(L) * cos(e) );
   if (RA < 0.0)
      RA += PI;
   if (L > PI)
      RA += PI;
   RA = 24.0 * RA / PI2;

   *DK = asin( sin(e) * sin(L) );

   // Damit 0 <= RA_Mittel < 24
   RA_Mittel = 24.0 * InPi( PI2 * RA_Mittel / 24.0) / PI2;

   dRA = RA_Mittel - RA;
   if (dRA < -12.0)
      dRA += 24.0;
   if (dRA > 12.0)
      dRA -= 24.0;

   dRA = dRA * 1.0027379;

   return dRA ;
}

void compute_s0( void )
{
   float u;
      
   compute_sonnenzeiten( clock_s.year + 2000, clock_s.mon, clock_s.day, clock_s.wday);
   clock_s.sa = (int)Aufgang;
   u = fmod( Aufgang, clock_s.sa) * 60;
   clock_s.sa *= 60;
   clock_s.sa += (int)u;
   clock_s.su = (int)Untergang;
   u = fmod( Untergang, clock_s.su) * 60;
   clock_s.su *= 60;
   clock_s.su += (int)u;
   clock_s.gflag |= 0x01;
}  

void compute_s1( void )
{
   float u;
   unsigned char jahr, monat, tag;
       
   monat = clock_s.mon;
   jahr = clock_s.year;
   if ( jahr % 4 == 0 && jahr > 0 )
      mtab[1] = 29;
   else
      mtab[1] = 28;

   tag = clock_s.day + 1;
   if ( tag > mtab[monat-1] )
   {
      tag = 1;
      monat += 1;
      if ( monat > 12 )
      {
         monat = 1;
         jahr += 1;
      }
   }
   compute_sonnenzeiten( jahr + 2000, monat, tag, clock_s.wday+1);
   clock_s.sa1 = (int)Aufgang;
   u = fmod( Aufgang, clock_s.sa1) * 60;
   clock_s.sa1 *= 60;
   clock_s.sa1 += (int)u;
   clock_s.su1 = (int)Untergang;
   u = fmod( Untergang, clock_s.su1) * 60;
   clock_s.su1 *= 60;
   clock_s.su1 += (int)u;
   clock_s.gflag |= 0x02;        
}          
#endif
 