/****************************************************************************
* main.c
* Frequenz Counter und dcf77 Uhr mit dem Atmega168
* Quarz mit 18,432 MHz: je höher je besser
* -------------------------------------------------------------------------------------------
* Address      Interrupt Definition              Benutzt   warum
* -------------------------------------------------------------------------------------------
* RESET        External Pin Reset
* INT0         External Interrupt Request 0      clock.c   DCF77 Impuls Auswertung
* INT1         External Interrupt Request 1
* PCINT0       Pin Change Interrupt Request 0
* PCINT1       Pin Change Interrupt Request 1
* PCINT2       Pin Change Interrupt Request 2
* WDT          Watchdog Time-out Interrupt
* TIMER2 COMPA Timer/Counter2 Compare Match A    abc/clock.c     10 msek
* TIMER2 COMPB Timer/Counter2 Compare Match B
* TIMER2 OVF   Timer/Counter2 Overflow
* TIMER1 CAPT  Timer/Counter1 Capture Event
* TIMER1 COMPA Timer/Counter1 Compare Match A
* TIMER1 COMPB Timer/Coutner1 Compare Match B
* TIMER1 OVF   Timer/Counter1 Overflow           main.c    Frequenz Messung
* TIMER0 COMPA Timer/Counter0 Compare Match A    abc/lcd.c Helligkeit wenn Uhr 
* TIMER0 COMPB Timer/Counter0 Compare Match B
* TIMER0 OVF   Timer/Counter0 Overflow           main.c    Pulsweiten Messung
* SPI          SPI Serial Transfer Complete
* USART_RX     Rx Complete
* USART_UDRE   Data Register Empty
* USART_TX     Tx Complete
*
* -------------------------------------------------------------------------------------------
* DCF77 Uhr oder Frequenz Counter
*
* ab V20  Prozessor:  ATmega168, Frequenz: 18,432 MHz
*
*                                      +-------------------+
* Reset           (PCINT14/RESET) PC6 -|1       XXX      28|- PC5 ((ADC5/SCL/PCINT13) LED DCF77
*                                      |                   |
*                   (PCINT16/RXD) PD0 -|2                27|- PC4 (ADC4/SDA/PCINT12)
*                                      |                   |
*                   (PCINT17/TXD) PD1 -|3                26|- PC3 (ADC3/PCINT11)      Backlight Control
*                                      |                   |
* DCF77 in         (PCINT18/INT0) PD2 -|4                25|- PC2 (ADC2/PCINT10)      LCD_CP data
*                                      |                   |
*             (PCINT19/OC2B/INT1) PD3 -|5                24|- PC1 (ADC1/PCINT9)       LCD_EN Enable
*                                      |                   |
* Pulsweite      (PCINT20/XCK/T0) PD4 -|6                23|- PC0 (ADC0/PCINT8)       LCD_DA Clock
*                                      |                   |
*                                 VCC -|7                22|- GND
*                                      |                   |
*                                 GND -|8   ATmega168    21|- AREF
*                                      |                   |
* 18,432 MHz (PCINT6/XTAL1/TOSC1) PB6 -|9                20|- AVCC
*                                      |                   |
* 18,432 MHz (PCINT7/XTAL2/TOSC2) PB7 -|10               19|- PB5 (SCK/PCINT5)
*                                      |                   |
* Freq. In      (PCINT21/OC0B/T1) PD5 -|11               18|- PB4 (MISO/PCINT4)
*                                      |                   |
* Vorteiler   (PCINT22/OC0A/AIN0) PD6 -|12               17|- PB3 (MOSI/OC2A/PCINT3)
*                                      |                   |
* S2 Taster        (PCINT23/AIN1) PD7 -|13               16|- PB2 (SS/OC1B/PCINT2)
*                                      |                   |
* S3 Taster    (PCINT0/CLKO/ICP1) PB0 -|14               15|- PB1 (OC1A/PCINT1)       S1 Kippschalter
*                                      +-------------------+
* -------------------------------------------------------------------------------------------
* 28.03.2009 li Tasten gedrueckt: schalten von VCC nach 0
* 19.04.2009 li Test mit DCF77 Modul von Conrad
* 23.04.2009 li S2 an PD7 und S3 an PB0
* 26.04.2009 li S1 an PB1
* 28.04.2009 li Timer1 Overflow OK
* 28.04.2009 li Alles OK
* 29.04.2009 li UHR: 4 Zustaende Beleuchtung
* 29.04.2009 li Frequenz: 4 Pulsdauer Messungen dazu
* 30.04.2009 li Pulsdauer ueber timer0 geht
* 02.05.2009 li menu steuerung neu
* 03.05.2009 li menu fertig
* 04.05.2009 li funktion display_menu dazu
* 06.05.2009 li korrektur start_frequ_messung(), timer2_init dazu
* 21.05.2009 li Sleep Mod DCF77 Uhr: Jeweils zur vollen Stunde DCF77 auswerten
* 22.05.2009 li µsek in der Anzeige
* 23.05.2009 li timer2 Sekunden Int: Quarz 6144000 Fehler korrigiert
* 26.05.2009 li Beschreibungen verbessert
* 12.10.2009 li Teiler Parameter neu, Pulsweitenmessung: timer0 mit Vorteiler 8 statt 64
* 16.10.2009 li Speicherung der Parameter in interne eeprom
* 17.10.2009 li Anzeige verbessert
* 07.11.2009 li V18: kleine Bereinigungen
* 03.03.2010 li V19: clock Verbesserung bei Stoerung DCF77 Signal
* 03.08.2010 li V20: float variable bei Pulsweitenberechnung
* 08.08.2010 li V21: Quarz 14,7456 MHz
* 11.08.2010 li V22: 10msek Int mit Timer2, counter1 = Frequ, counter0 = Pulsweite
* 17.08.2010 li V23: PGMSPACE used
* 18.08.2010 li V24: Quarz 18,432 MHz
* 20.08.2010 li V25: LCD Backlight controller verbessert
* 16.11.2010 li V26: Messungen 8MHz im automodus mist
* 21.12.2010 li V27: DCF77 Uhr korrigiert
* 30.01.2011 li V28: Sonnenauf- und Untergang eingebaut
* 31.01.2011 li V29: jetzt mit abc/clock.c
* 03.02.2011 li V30: Freq. Messung Fehler ...
* 10.06.2012 li V31: Display Helligkeit wenn Uhr... 
*/

#include <util/delay.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include "../abc/lcd.h"       // makefile: "CDEFS += DA_DCF77" zur Definition der LCD Bits
#include "../abc/clock.h"
#include "../abc/basis.h"

void timer2_init(void);
void display_frqu(void);
void display_frqu1( unsigned long value );
void display_frqu2( unsigned long value );
void edit_zahl(unsigned long value, unsigned char edit);
void start_frequ_messung(void);
void stop_frequ_messung(void);
void menu_U_sw2( void );
void menu_F_sw2( void );
void display_menu(unsigned char m1);
void move2( char l, char pos, char index, unsigned char quelle );
void move1( char l, char index  );
void save_eeprom( void );
unsigned char test_switch_D( unsigned char i );
unsigned char test_switch_B( unsigned char i );
void s2_todo(void);
void s3_todo(void);
void clear_zeile( char *);
void change_flag( unsigned char pos );


int clock_sync = 0;                    // Werte bis 1000
int clock_stopp = 200;                 // Werte bis 1000, Fehlwert 2 Sekunden
unsigned char intervall = 2;           // intervall dauer
unsigned char t0p = 1;

unsigned char fmode = 2;               // auto
unsigned char zmode = 1;               // vorteiler Ziel mode
unsigned char pmode = 1;               // vorteiler Messung Mode
unsigned char rpm_teiler = 1;          // zusaetzlicher teiler wenn rpm Messungen
unsigned char pulse_messung = 0;       // Pulse positiv oder negativ

                                       // t0 8 Bit counter
volatile long t0over = 0;              // t0 int overflow
volatile long t0ovs  = 0;              // t0 save overflow counter
volatile unsigned char t0cnt  = 0;     // t0 Counter

                                       // t1 = 16 Bit counter
volatile unsigned int t1over = 0;      // t1 int overflow
volatile unsigned int t1ovs  = 0;      // t1 save overflow counter
volatile unsigned int t1cnt  = 0;      // t1 Counter

unsigned char fflag = 0;               // Signal display Messung
unsigned char aflag = 0;

unsigned char t1vtm = 0;               // vorteiler Modus Messung
unsigned char ftrace = 0;              // trace Modus frequenz

  // ----------------------------------------------
  // INDEX test_switch_x()     0     1     2
  // ----------------------------------------------
unsigned char al_cc[3]  = {    0,    0,    0  };
unsigned char al_bit[3] = { BIT1, BIT7, BIT0 };
 //                           S1    S2   S3


unsigned char s1_toggle = 0;          // 0=DCF77 Uhr, 1=Frequenzcounter
extern unsigned char dcf_flash;       // DCF77 Impuls als LCD
unsigned char backlight = 0;          // Hintergrundbeleuchtung LCD

unsigned char t2_korr = 1;

#if LCD_CHARS == 16
                   /* 0123456789012345 */
char zeile11[ 17 ] = "                " ;
char zeile12[ 17 ] = "                " ;
#else
                   /* 01234567890123456789 */
char zeile11[ 21 ] = "                    " ;
char zeile12[ 21 ] = "                    " ;
#endif
                            //012345    menu clock
static char m_t1[] PROGMEM = "ret31 "
                             "Licht "   // 1
                             "P LED "   // 2
                             "Sleep "   // 3
                             "Trace ";  // 4

                            //012345    menu Frequenzcounter
static char m_t2[] PROGMEM = "ret31 "   // 0
                             "Modus "   // 1
                             "Cycle "   // 2
                             "Teiler"   // 3
                             "Licht "   // 4
                             "Trace "   // 5
                             "Pulse ";  // 6

                             //012      sub menu diverses
static char sm_t1[] PROGMEM = "ret"     // 0
                              "aus"     // 1
                              "ein";    // 2

                              //012345   submenu Freq: Modus
static char sm_t21[] PROGMEM = "retur "  // 0
                               "F o.VT"  // 1
                               "F m.VT"  // 2
                               "F auto"  // 3
                               "Drehz."; // 4

                              //0123    submenu Freq: Cycle Time
static char sm_t22[] PROGMEM = "ret "   // 0
                               " 1 s"   // 1
                               " 2 s"   // 2
                               " 4 s"   // 3
                               "10 s";  // 4

                              //012     submenu Teiler
static char sm_t23[] PROGMEM = "ret"    // 0
                               " 1 "    // 1
                               " 2 ";   // 2

                              //012     submenu Trace
static char sm_t24[] PROGMEM = "ret"    // 0
                               "aus"    // 1
                               "T1 "    // 2
                               "T2 ";   // 3

                              //0123456   submenu Pulse
static char sm_t25[] PROGMEM = "retur  "  // 0
                               "Positiv"  // 1
                               "Negativ"  // 2
                               "Cycle  "; // 3
                               
                     // 01234     submenu Licht reale Leistung in %
char sm_t2[] PROGMEM = "ret  "    // 0
                       "aus  "    // 1
                       "12,5%"    // 2
                       "25,0%"    // 3
                       "50,0%"    // 4
                       "99,9%";   // 5 
                       
#define LEN_SM_T2  5
#define ENT_SM_T2  5     // Anzahl der Eintraege -1                               


unsigned char time_liste[ 4 ]   = { 1, 2, 4, 10 } ;
unsigned char teiler_liste[ 2 ] = { 1, 2 } ;

                        // Laengen Definitionen
#define LEN_M_T1   6
#define LEN_M_T2   6
#define LEN_SM_T1  3
#define LEN_SM_T21 6
#define LEN_SM_T22 4
#define LEN_SM_T23 3
#define LEN_SM_T24 3
#define LEN_SM_T25 7
                        // Anzahl der Eintraege -1
#define ENT_M_T1   4    // clock
#define ENT_M_T2   6    // frequ
#define ENT_SM_T1  2
#define ENT_SM_T21 4
#define ENT_SM_T22 4
#define ENT_SM_T23 2
#define ENT_SM_T24 3
#define ENT_SM_T25 3
                        // Index auf den Subtext
#define INDEX_SM_T1  1
#define INDEX_SM_T21 2
#define INDEX_SM_T22 3
#define INDEX_SM_T23 4
#define INDEX_SM_T24 5
#define INDEX_SM_T25 6
#define INDEX_SM_T2  7 

#define S1_CNTL_DDR  DDRB
#define S1_CNTL_PORT PORTB
#define S1_CNTL_PIN  PINB
#define S1_CNTL_BIT  BIT1

volatile unsigned char menu_aktiv = 0;    // menu aktiv
unsigned char mtime = 0;         // menu nach 10 Sekunden weg
unsigned char menu1 = 0;         // mm3 sicherung text1
unsigned char mm3 = 0;           // s3: index auf texte
unsigned char mm2 = 0;           // s2: press counter

unsigned char mm3max[2];         // s3: max index text1
unsigned char mmxlen[2];
unsigned char mmxs1 = 1;         // index auf submenu texte

unsigned int  lcd_timer = 1;     // lcd Timer

extern volatile S_LCD_ANZ lcdanz_s;
extern volatile S_CLOCK   clock_s;

int volatile eeprom_timer = 5;
unsigned char eeprom_read_ok = 0;
unsigned char tim2sek = 0 ;

// EEPROM Speicher ---------------------------------------------------------
                         //   0   1   2   3   4   5   6   7   8
uint8_t eeByte[10] EEMEM =  {'0','0','0','0','0','0','0','6','0'};
                         //   I   I   I       I   I   I   I   I=pruefzahl
                         //   I   I   I       I   I   I   I=Sleep_Sw
                         //   I   I   I       I   I   I=dcf_flash (LED)
                         //   I   I   I       I   I=lcd_backlight
                         //   I   I   I       I=teiler
                         //   I   I   I=intervall
                         //   I   I=pmode
                         //   I=fmode
// -------------------------------------------------------------------------
char eep[10] ;           // transfer area to eeprom


/*****************************************************************************
* 30.04.2009 li Neue Menue Struktur
*               S3 = untere Taste Menue Auswahl
*               S2 = Ausgewaehlen Punkt bestaetigen
*
*               Aufbau in der ersten Zeile:
* Uhr ---------------------------------------------------------------------
*
* S3 = Licht / P LED / Sleep  / Trace
*      !       !       !      !- retur / aus / ein
*      !       !       !- retur / aus / ein
*      !       !- retur / aus / ein
*      !- retur / aus / 12,5% / 25,0% / 50,0%  / 99,9%
*
*
* Frequenzzaehler ---------------------------------------------------------
*
* S3 = Modus / Cycle / Teiler / Licht  / Trace / Pulse
*      !       !       !        !        !       !- retur / Positiv / Negativ / Cycle
*      !       !       !        !        !- retur / aus / ein
*      !       !       !        !- retur / aus / ein
*      !       !       !- ret / 1 / 2
*      !       !- retur / 1 / 2 / 4 / 10 Sekunden
*      !- retur / ohne VT / mit VT / auto  / Drehz.
*/
int main(void)
{
   unsigned char n , p2;

   // lcd_init(1);                // Initialize LC-Display siehe stop_freq
   timer2_init();                 // 10 msec Intervall Int starten
   dcf_flash = 1;                 // Pulse

   sei();                         // enable int

   DDRD  |= BIT6 ;                // BIT6 PortD (PIN12) Vorteiler, Output
   DDRD  &= ~(BIT4+BIT5+BIT7);    // BIT5 PortD (PIN11) Frequenz Input, S2
   PORTD &= ~(BIT4+BIT5+BIT7);    // ohne internen Pullup

   DDRB  &= ~(BIT0+BIT1);         // S1, S3
   PORTB &= ~(BIT0+BIT1);         // ohne internen Pullup

   stop_frequ_messung();
   lcd_beleuchtung( backlight );
   lcd_clear();
   lcd_home();
   start_clock();
   clock_s.Sleep_Sw = 1;          // nur alle Stunden auswerten
   clock_s.display_flag = 3;      // beide zeilen anzeigen

   // ++++++++++++++++++++++++++++++++ Main LOOP ++++++++++++++++++++++++++++
   for(;;)
   {
      if ( clock_s.tim2ovf )         // Timer2 overflow (10msec) ??
      {
         if ( s1_toggle == 0 )       // ********* DCF77 *********
         {
            timer2_signal();         // dcf77 clock benachrichtigen
         }
         else                        // ******* Frequenz Counter **
         {
            clock_s.tim2ovf = 0;     // reset flag
            if ( fflag )             // cycle time over
            {
               if ( menu_aktiv == 0 )
                  display_frqu();    // Messung anzeigen
               fflag = 0;
            }
         }
                                     // ++++++++ Schalter Abfragen 10 msec

         if ( test_switch_D(1) == 1 )  // ++ S2 +++
            s2_todo();

         if ( test_switch_B(2) == 1 )  // ++ S3 +++
            s3_todo();

         if ( ++tim2sek >= 100 )      // Sekunden interupt da ??
         {
            tim2sek = 0;
                                      // Hier alle 1000 msek --------------------------------------------------------
            eeprom_timer--;
            if ( eeprom_timer == 0 )
            {
               eeprom_read_ok = 0;
               eeprom_timer = 28800 ;       // alle 8 Stunden auslesen
               for( n=0; n < 9; n++)
                  eep[n] = eeprom_read_byte( &eeByte[n] );
               p2  = berechne_PZ( eep, 8) + 0x30 ;
               if ( eep[8] == p2)          // pruefzahl OK ?
               {
                  eeprom_read_ok = 1;
                  fmode = eep[0] & 0x0F;
                  pmode = eep[1] & 0x0F;
                  intervall = a_to_i( eep+2, 2);
                  rpm_teiler = eep[4] & 0x0F;
                  backlight = eep[5] & 0x0F;
                  lcd_beleuchtung( backlight );
                  dcf_flash = eep[6] & 0x0F;
                  clock_s.Sleep_Sw = eep[7] & 0x0F;
               }
            }

            if ( menu_aktiv )        // reset menu nach 10Sek
            {
               if ( mtime++ > 10 )
               {
                  menu_aktiv = 0;
                  mtime = 0;
                  mm3 = 0;
                  mm2 = 0;
                  if ( s1_toggle == 0 )
                  {
                     clock_s.display_flag = 3;      // beide zeilen anzeigen
                     start_clock();
                  }
                  else
                     display_frqu();  // Messung anzeigen
               }
            }

            if ( lcd_timer )
            {
               if ( lcd_timer++ > 3600  )        // 1 Stunde vorbei ?
               {
                  lcd_timer = 0;
                  lcd_beleuchtung( backlight );  // Beleuchtung aus/ein
               }
            }
         }
      }
      // ++++++++++++++++++++++++++++ S1 ++++++++++++++++++++++++++
      // S1 Kipp Schalter: 1 = Vorteilerboard hat +5V
      if ( S1_CNTL_PIN & S1_CNTL_BIT && s1_toggle == 0 )
      {
         _delay_us( 500.0 );
         if ( S1_CNTL_PIN & S1_CNTL_BIT  )
         {
            if ( al_cc[0] > 50 )
            {
               al_cc[0] = 0;     // clear
               s1_toggle = 1;    // s1 switch auf Frequenzcounter
               mm2 = 0;
               mm3 = 0;
               stopp_clock();
               start_frequ_messung();
               lcd_clear();
               lcd_home();
               display_frqu();
            }
            else
               al_cc[0]++;
         }
      }

      if ( !(S1_CNTL_PIN & S1_CNTL_BIT) && s1_toggle == 1 )
      {
         _delay_us( 500.0 );
         if ( !(S1_CNTL_PIN & S1_CNTL_BIT) )
         {
            if ( al_cc[0] > 50 )
            {
               al_cc[0] = 0;    // clear
               s1_toggle = 0;   // switched auf DCF77 Uhr
               mm2 = 0;
               mm3 = 0;
               stop_frequ_messung();
               lcd_clear();
               lcd_home();
               clock_s.dcf_flag = 0;
               clock_s.dmm = 0;           // Minute  
               clock_s.dhh = 0;           // Stunde 
               clock_s.day = 0;           // Tag
               clock_s.wday = 0;          // Wochentag
               clock_s.mon = 0;           // Monat
               clock_s.year = 0;          // Jahr
               clock_s.dmz = 0;           // Jahr
               start_clock();
               clock_s.display_flag = 3;      // beide zeilen anzeigen
            }
            else
               al_cc[0]++;
         }
      }

   }
}



/*****************************************************************************
** S3 Menu
*/
void s3_todo( void )
{
   lcd_beleuchtung( 4 );         // 10.9.2009 Beleuchtung ein
   lcd_timer = 1;                // timer starten
   menu_aktiv = 1;
   clock_s.display_flag = 2;     // eine zeilen anzeigen
   mtime = 0;
   mm3++;

   if ( mm2 == 0 )               // kein s2 switch da
   {                             // default werte einstellen
      if ( s1_toggle == 0 )      // DCF77 Menu
      {
         mmxlen[0] = LEN_M_T1;
         mm3max[0] = ENT_M_T1;
         mmxlen[1] = LEN_SM_T1;
         mm3max[1] = ENT_SM_T1;
         mmxs1 = INDEX_SM_T1;

      }
      else                       // frequenz counter Menu
      {
         mmxlen[0] = LEN_M_T2;
         mm3max[0] = ENT_M_T2;
         mmxlen[1] = LEN_SM_T1;
         mm3max[1] = ENT_SM_T1;
         mmxs1 = INDEX_SM_T1;
      }
   }
   if ( mm3 > mm3max[mm2] )
      mm3 = 0;

   if ( mm2 == 0 )
   {
      if ( s1_toggle == 1 )      // frequenz counter
      {
         switch( mm3 )
         {
           case 1:
            mmxlen[1] = LEN_SM_T21;
            mm3max[1] = ENT_SM_T21;
            mmxs1 = INDEX_SM_T21;   // sm_t21;
            break;

           case 2:
            mmxlen[1] = LEN_SM_T22;
            mm3max[1] = ENT_SM_T22;
            mmxs1 = INDEX_SM_T22;   // sm_t22;
            break;

           case 3:
            mmxlen[1] = LEN_SM_T23;
            mm3max[1] = ENT_SM_T23;
            mmxs1 = INDEX_SM_T23;   // sm_t23;
            break;
            
           case 5:                     // -------- Trace
            mmxlen[1] = LEN_SM_T24;
            mm3max[1] = ENT_SM_T24;
            mmxs1 = INDEX_SM_T24;   // sm_t24;
            break;

           case 6:                     // -------- Pulse
            mmxlen[1] = LEN_SM_T25;
            mm3max[1] = ENT_SM_T25;
            mmxs1 = INDEX_SM_T25;   // sm_t25;
            break;

           default:
            mmxlen[1] = LEN_SM_T1;
            mm3max[1] = ENT_SM_T1;
            mmxs1 = INDEX_SM_T1;    //  sm_t1;
            break;
         }
      }
      else                          // DCF77
      {
         switch( mm3 )
         {
           case 1:
            mmxlen[1] = LEN_SM_T2;
            mm3max[1] = ENT_SM_T2;
            mmxs1 = INDEX_SM_T2;   // sm_t2;
            break;
           
           default:
            mmxlen[1] = LEN_SM_T1;
            mm3max[1] = ENT_SM_T1;
            mmxs1 = INDEX_SM_T1;       //  sm_t1;
            break;
         }
      }
      display_menu( mm3 );          // text1
   }
   else
      display_menu( menu1 );        // text 1 und text2
}



/*****************************************************************************
** S2 Menu
*/
void s2_todo( void )
{
   unsigned char i;

   lcd_beleuchtung( 4 );         // 10.9.2009 Beleuchtung ein
   lcd_timer = 1;                // timer starten

   if ( menu_aktiv )             // s3 da gewesen  ??
   {
      mtime = 0;                 // restart mtime
      mm2++;
      if ( mm2 == 1 )            // erster text da
      {
         menu1 = mm3;            // save level 1
                                 // das was da ist anzeigen
         if ( s1_toggle == 0 )   // DCF77 Menu
         {
            switch( menu1 )      // Anzeige submenu mit currend Einstellung
            {
              case 0: mm3 = 0; menu_U_sw2(); break;    // DCF77 Menu break;
              case 1: mm3=backlight+1; break;          // licht
              case 2: mm3=dcf_flash +1; break;         // LED
              case 3: mm3=clock_s.Sleep_Sw+1; break;   // Sleep Switch
              case 4: mm3=clock_s.time_trace+1; break;         // trace
            }
         }
         else                    // frequenz counter
         {
            switch( menu1 )      // Anzeige submenu mit currend Einstellung
            {
              case 0: mm3 = 0; menu_F_sw2(); break;
              case 1: mm3=fmode+1; break;        // Messung
              case 2:                            // intervall
               for ( i=0; i<4; i++ )
               {
                  if ( intervall == time_liste[i] )
                  {
                     mm3 = i+1;
                     break;
                  }
               }
               break;

              case 3:            // Teiler Liste
               for ( i=0; i<2; i++ )
               {
                  if ( rpm_teiler == teiler_liste[i] )
                  {
                     mm3 = i+1;
                     break;
                  }
               }
               break;

              case 4: mm3 = backlight+1; break;  // Licht
              case 5: mm3 = ftrace+1; break;         // trace
              case 6: mm3 = pulse_messung+1; break;  // Pulse Messung
            }
         }
         if ( mm3 )
         {
            display_menu( menu1 );   // text1 und text2
         }
      }
      else
      {
         mm2 = 1;                // mm2 auf 1 halten
         if ( s1_toggle == 0 )
            menu_U_sw2();        // DCF77 Menu
         else
            menu_F_sw2();        // Frequenz Menu
      }
   }
}



/*****************************************************************************
** Frequenz: Taste 2 pressed
** return 1 = Zeit normal anzeigen
**        0 = Menu Zeile anzeigen
**
** die text elemente sind so angeordnet, dass bei "ein" todo=1 ist, "aus" todo=0
*/
void menu_F_sw2( void )
{
   unsigned char rc=1;
   unsigned char todo;

   todo = mm3 - 1;               // mm3 = Index der Anzeige

   mm2 = 0;
   if ( menu1 )                  // menu 1
   {
      if ( todo == 0xFF )        // retur ausgewaehlt ?
         display_menu( menu1 );
      else
      {
         switch ( menu1 )
         {
           case 1:
            fmode = todo;
            if ( fmode == 1 || fmode == 2)
               pmode = 1;        // vorteiler ein
            else
               pmode = 0;        // vorteiler aus
            save_eeprom();
            break;               // Messung

           case 2:
            intervall = time_liste[todo] ;  // Zeit umsetzen
            clock_stopp = intervall * 100;
            save_eeprom();
            break;               // intervall

           case 3:
            rpm_teiler = teiler_liste[todo] ;  // teiler umsetzen
            save_eeprom();
            break;

           case 4:
            backlight = todo;
            lcd_beleuchtung( backlight );
            save_eeprom();
            break;               // backlight

           case 5:
            ftrace = todo;
            break;               // trace

           case 6:
            pulse_messung = todo;
            break;               // trace
         }
      }
   }
   if ( rc )
   {
      mtime = 0;
      mm3 = 0;
      menu_aktiv = 0;
      start_frequ_messung();     // frequenz Messung restart
      display_frqu();
   }
}



/*****************************************************************************
** DCF77 Uhr: Taste 2 pressed
** return 1 = Messung anzeigen
**        0 = Menu Zeile anzeigen
**
** die text elemente sind so angeordnet, dass bei "ein" todo=1 ist, "aus" todo=0
**
** menu1 = 0  und mm3 = 0
*/
void menu_U_sw2( void )
{
   unsigned char rc=1;
   unsigned char todo;

   mm2 = 0;             // mm2 immer auf 0
   if ( menu1 )                      // menu 1
   {
      todo = mm3 - 1;
      if ( todo == 0xff )            // retur ausgewaehlt ?
      {
         display_menu( menu1 );
         rc=0;
      }
      else
      {
         switch ( menu1 )
         {
           case 1:
            backlight = todo;
            lcd_beleuchtung( backlight );
            save_eeprom();
            break;  // licht

           case 2: dcf_flash  = todo;
            save_eeprom();
            break;        // LED

           case 3:
            clock_s.Sleep_Sw = todo;
            if ( clock_s.Sleep_Sw )
            {
               if ( clock_s.dmm < 56 )
                  stopp_clock();
            }
            else
               start_clock();
            save_eeprom();
            break;        // sleep modus

           case 4:
            clock_s.time_trace = todo;
            break;        // trace
         }
      }
   }
   if ( rc )
   {
      mm3 = 0;          // mm3 wieder auf 0
      mtime = 0;
      menu_aktiv = 0;
      clock_s.display_flag = 3;     // eine zeilen anzeigen
      start_clock();
   }
}



/*****************************************************************************
**  Menu Zeile erzeugen und anzeigen
*/
void display_menu( unsigned char m1 )
{
   clear_zeile(zeile11);

   move1( mmxlen[0], m1  );      // move text1

   if ( mm2 )
   {
      move2( mmxlen[1], mmxlen[0]+1, mm3, mmxs1 ); // move text2
   }
   set_cursor( 0, 1 );          // Hier in Zeile 3
   lcd_string( zeile11 );
}



/*****************************************************************************
**  Text nach zeile11 kopieren
*/
void move1( char l, char index  )
{
   unsigned char n,q;
   prog_char *addr;

   if ( s1_toggle == 0 )
      addr = (prog_char*)&m_t1;   // DCF77 Menu
   else
      addr = (prog_char*)&m_t2;   // Frequ Menu

   q = index * l;                 // quell Position
   addr += q;
   for( n = 0; n < l ; n++)
   {
      zeile11[n] = pgm_read_byte( addr++ );
   }
}



/*****************************************************************************
**  Text2 nach zeile11 kopieren
**  9.3.2010 pgmspace
*/
void move2( char l, char pos, char index, unsigned char quelle )
{
   char n,q;
   prog_char *addr;

   addr = (prog_char*)&sm_t1;

   switch ( quelle )
   {
     case INDEX_SM_T21: addr = (prog_char*)&sm_t21; break;
     case INDEX_SM_T22: addr = (prog_char*)&sm_t22; break;
     case INDEX_SM_T23: addr = (prog_char*)&sm_t23; break;
     case INDEX_SM_T24: addr = (prog_char*)&sm_t24; break;
     case INDEX_SM_T25: addr = (prog_char*)&sm_t25; break;
     case INDEX_SM_T2:  addr = (prog_char*)&sm_t2; break;
   }

   q = index * l;            // quell Position
   addr += q;
   for( n = 0; n < l ; n++)
   {
      zeile11[pos+n] = pgm_read_byte( addr++ );
   }
}



/*****************************************************************************
**  Frequenz display, Zeilen 1 bis 4
*/
void display_frqu(void)
{
   unsigned long value;
   unsigned long freq;

   value = t1ovs ;              // gesicherter Overflow Counter
   value <<= 16  ;              // * 65536
   value += t1cnt;              // + restmenge TCNT1

   if ( t1vtm )                 // Messung mit Vorteiler
      value *= 16;              // count * 16

   freq = value / intervall;

   if ( fmode == 2 )            // auto Modus ??
   {
      if ( freq < 256000 )      // kleiner 256khz ?
         pmode = 0;             // vorteiler aus
      else
         pmode = 1;
   }

   display_frqu1( value );      // Frequenz / rpm

   if ( freq < 200000 )
      display_frqu2( value );   // Pulsweite in %
   else
   {
      clear_zeile(zeile12);
      set_cursor( 0, 2 );
      lcd_string( zeile12 );
   }

   if ( ftrace )           // Trace Modus
   {
      clear_zeile(zeile11);

      if ( ftrace == 1 )           // Trace Modus t1 counter
      {
         zeile11[0] = 'T';
         zeile11[1] = '1';
         edit_hex( 4, t1ovs, zeile11+3 );
         edit_hex( 4, t1cnt, zeile11+8 );
      }
      else
      {
         zeile11[0] = 'T';
         zeile11[1] = '2';
         edit_hex( 8, t0ovs, zeile11+3 );
         edit_hex( 2, t0cnt, zeile11+12 );
      }                          // Soll modus
      set_cursor( 0, 2 );
      lcd_string( zeile11 );
   }
}



/*****************************************************************************
** Frequenz Messung anzeigen
** Wenn cycletime 10 Sekunden, dann F mit Nachkommastelle
** Soll Modus fmode: 0  ohne vorteiler
*                    1  Mit Vorteiler 16
*                    2  auto
*                    3  Messung rpm ohne Vorteiler
*/
void display_frqu1( unsigned long value)
{
   unsigned char x;
   unsigned long wert,rest;
   unsigned amode ;

   amode = fmode;

   wert = value;

   clear_zeile(zeile11);

   if ( amode == 3 )               // rpm
   {
      zeile11[0] = 'R';
      zeile11[1] = '1';
      x = rpm_teiler + 0x30 ;
      if ( x > 0x39 )
         x += 0x07 ;
      zeile11[3] = x ;
      change_flag(2);
   }
   else
   {
      zeile11[0] = 'F';
      zeile11[2] = '1' ;
      if ( t1vtm )                // mit
         zeile11[3] = '6' ;
      change_flag( 1 );
   }

   switch ( intervall )
   {
     case 1:
      if ( amode == 3 )
      {
         wert *= 60 ;       // rpm: werte mal 60
      }
      break;

     case 2:
      if ( amode == 3 )
      {
         wert *= 30 ;       // rpm: 2 * 30 = 60
      }
      else
      {
         wert += 1;         // runden
         wert /= 2;         // Intervall alle 2 Sekunden
      }
      break;

     case 4:
      if ( amode == 3 )
      {
         wert *= 15 ;     // rpm: 4 * 15 = 60
      }
      else
      {
         wert += 3;         // runden
         wert /= 4;         // Intervall alle 4 Sekunden
      }
      break;

     case 10:
      if ( amode == 3 )
      {
         wert *= 60  ;      // rpm: 10 * 6 = 60
      }
      break;
   }

   switch ( amode )
   {
     case 0:                     // frequenz in Hz
     case 1:
     case 2:
      if ( wert > 10000 )
      {
         wert /= 100;
         zeile11[13] = 'k' ;
         zeile11[14] = 'H' ;
         zeile11[15] = 'z' ;
      }
      else
      {
         zeile11[13] = 'H' ;
         zeile11[14] = 'z' ;
      }
      break;

     case 3:                     // rpm Mode
      zeile11[13] = 'r' ;
      zeile11[14] = 'p' ;
      zeile11[15] = 'm' ;
      wert /= rpm_teiler;       // 16.10.2009 rpm Wert teilen
      break;
   }

   if ( intervall == 10 )
   {
      if ( zeile11[13] == 'k' )
      {
         rest = wert % 100;
         wert /= 100;
         zeile11[ 10 ] = ',';
         edit99( rest, zeile11+11, 2 );
         edit99( wert, zeile11+5, 5 );

         if ( zeile11[ 5 ] == '0' )
         {
            zeile11[ 5 ] = ' ';
            if ( zeile11[ 6 ] == '0' )
            {
               zeile11[ 6 ] = ' ';
               if ( zeile11[ 7 ] == '0' )
               {
                  zeile11[ 7 ] = ' ';
                  if ( zeile11[ 8 ] == '0' )
                     zeile11[ 8 ] = ' ';
               }
            }
         }
      }
      else
      {
         rest = wert % 10;
         wert /= 10;
         zeile11[ 11 ] = ',';
         zeile11[12] = rest + 0x30 ;
         edit99( wert, zeile11+5, 6 );

         if ( zeile11[ 5 ] == '0' )
         {
            zeile11[ 5 ] = ' ';
            if ( zeile11[ 6 ] == '0' )
            {
               zeile11[ 6 ] = ' ';
               if ( zeile11[ 7 ] == '0' )
               {
                  zeile11[ 7 ] = ' ';
                  if ( zeile11[ 8 ] == '0' )
                     zeile11[ 8 ] = ' ';
               }
            }
         }
      }
   }
   else if ( zeile11[13] == 'k' )
   {
      rest = wert % 10;
      wert /= 10;
      zeile11[ 10 ] = ',';
      zeile11[11] = rest + 0x30 ;
      edit99( wert, zeile11+5, 5 );

      if ( zeile11[ 5 ] == '0' )
      {
         zeile11[ 5 ] = ' ';
         if ( zeile11[ 6 ] == '0' )
         {
            zeile11[ 6 ] = ' ';
            if ( zeile11[ 7 ] == '0' )
            {
               zeile11[ 7 ] = ' ';
               if ( zeile11[ 8 ] == '0' )
                  zeile11[ 8 ] = ' ';
            }
         }
      }
   }
   else
   {
      edit99( wert, zeile11+6, 6 );
      if ( zeile11[ 6 ] == '0' )
      {
         zeile11[ 6 ] = ' ';
         if ( zeile11[ 7 ] == '0' )
         {
            zeile11[ 7 ] = ' ';
            if ( zeile11[ 8 ] == '0' )
            {
               zeile11[ 8 ] = ' ';
               if ( zeile11[ 9 ] == '0' )
               {
                  zeile11[ 9 ] = ' ';
                  if ( zeile11[ 10 ] == '0' )
                     zeile11[ 10 ] = ' ';
               }
            }
         }
      }
   }

   set_cursor( 0, 1 );
   lcd_string( zeile11 );
}



/*****************************************************************************
** intervall wechsel anzeigen
*/
void change_flag( unsigned char pos )
{
      if ( aflag )
#ifdef A_DCF77
         zeile11[pos] = 0x3E;        //  >
      else
         zeile11[pos] = 0x7E;        //  ->
#else
         zeile11[pos] = 0xFB;        //  backslash

      else
         zeile11[pos] = '/' ;
#endif
         aflag ^= 0x01 ;
}


      
/*****************************************************************************
** Pulsweite anzeigen, messung mit eigenem quarz von 6,144 MHz
** Wenn cycletime 10 Sekunden, dann Frequenz mit einer Nachkommastelle
** wenn pulse_messung = 1 dann negativ beechnen
*/
void display_frqu2( unsigned long value )
{
   float f100, fwert;
   unsigned long wert, rest;
   char ppp[4];

   clear_zeile(zeile12);
                               // value = cycles im Intervall
   f100 =  6144000.0 ;
  
   f100 *= intervall;
   if ( value )                // geteilt durch die Frequenz
      f100 /= value ;          // µsek / perioden

   fwert = t0ovs;
   fwert *= 256.0;
   fwert += t0cnt ;
   if ( value )                // geteilt durch die Frequenz
      fwert /= value ;         // µsek / perioden

   fwert *= 100.0;             // * 100
   fwert /= f100;              // Ergebnis in %
   if ( pulse_messung == 1)
      fwert = 100.0 - fwert;
   
   if ( fwert > 10.0  )
   {
      wert = fwert + 0.499;    // 
      edit99( wert, zeile12+1, 3 );
      if ( zeile12[ 1 ] == '0' )
      {
         zeile12[ 1 ] = ' ';
         if ( zeile12[ 2 ] == '0' )
            zeile12[ 2 ] = ' ';
      }
   }
   else
   {
      wert = ((fwert + 0.0499) * 10.0);       // 
      edit99( wert, ppp, 3 );
      zeile12[ 1 ] = ppp[1];
      zeile12[ 2 ] = ',';
      zeile12[ 3 ] = ppp[2];
   }
   
   zeile12[ 4 ] = '%' ;
   zeile12[ 0 ] = 'P' ;
   if ( pulse_messung == 1 )
       zeile12[ 0 ] = 'N' ;
   if ( pulse_messung == 2 )
       zeile12[ 0 ] = 'C' ;


   fwert = t0ovs;             // gesicherter overflow cnt
   fwert *= 256;              // mal 256 = Counter
   fwert += t0cnt ;           // + Restcount = Anzahl
   fwert /= 6.144;

   
   if ( value )               // geteilt durch die Frequenz
      fwert /= value ;        // µsek / perioden

   if ( pulse_messung )       // neagtiv ??
   {
      f100 = 1000000.0 ;
      f100 *= intervall;
      if ( value )            // geteilt durch die Frequenz
         f100 /= value ;      // µsek / perioden
      if ( pulse_messung == 2 )
         fwert = f100 ;
      else
         fwert = f100 - fwert;
   }

   if ( fwert > 150000.0 )
   {
      wert = fwert / 1000.0; // Ergebnis
      edit99( wert, zeile12+7, 5 );
      zeile12[12] = 'm' ;     // m Codierung auf dem LCD
      if ( zeile12[ 7 ] == '0' )
      {
         zeile12[ 7 ] = ' ';
         if ( zeile12[ 8 ] == '0' )
         {
            zeile12[ 8 ] = ' ';
            if ( zeile12[ 9 ] == '0' )
            {
               zeile12[ 9 ] = ' ';
               if ( zeile12[ 10 ] == '0' )
                  zeile12[ 10 ] = ' ';
            }
         }
      }
   }
   else if ( fwert > 1500.0 )
   {
      wert = fwert / 10.0;   // Ergebnis
      rest = wert % 100;
      edit99( rest, zeile12+10, 2 );
      zeile12[9] = ',' ;
      wert /= 100;
      edit99( wert, zeile12+6, 3 );
      if ( zeile12[ 6 ] == '0' )
      {
         zeile12[ 6 ] = ' ';
         if ( zeile12[ 7 ] == '0' )
         {
            zeile12[ 7 ] = ' ';
         }
      }
      zeile12[12] = 'm' ;     // m Codierung auf dem LCD
   }
   else
   {
      wert = fwert;
      edit99( wert, zeile12+7, 5 );
      zeile12[12] = 'u' ;     // u Codierung auf dem LCD
      if ( zeile12[ 7 ] == '0' )
      {
         zeile12[ 7 ] = ' ';
         if ( zeile12[ 8 ] == '0' )
         {
            zeile12[ 8 ] = ' ';
            if ( zeile12[ 9 ] == '0' )
            {
               zeile12[ 9 ] = ' ';
               if ( zeile12[ 10 ] == '0' )
                  zeile12[ 10 ] = ' ';
            }
         }
      }
   }
   zeile12[13] = 's' ;     // s Codierung auf dem LCD
   zeile12[14] = 'e' ;     // e Codierung auf dem LCD
   zeile12[15] = 'k' ;     // k Codierung auf dem LCD
   set_cursor( 0, 2 );
   lcd_string( zeile12 );
}



/*****************************************************************************
** Save der wichtigen Parameter im internen eeprom
*/
void save_eeprom( void )
{
   unsigned char n;

   eep[0] = fmode + 0x30 ;
   eep[1] = pmode + 0x30 ;
   edit99( intervall, eep+2, 2);
   eep[4] = rpm_teiler + 0x30 ;
   eep[5] = backlight + 0x30 ;
   eep[6] = dcf_flash + 0x30 ;
   eep[7] = clock_s.Sleep_Sw  + 0x30 ;
   eep[8] = berechne_PZ( eep, 8) + 0x30 ;
   for ( n=0; n < 9; n++)
   {
      eeprom_write_byte( &eeByte[n], eep[n] );
   }
   eeprom_timer = 5;
}



/*****************************************************************************
** clear Zeile
*/
void clear_zeile( char *s )
{
   unsigned char i;
#if LCD_CHARS == 16
   for( i=0; i < 16 ; i++ )
#else
   for( i=0; i < 20 ; i++ )
#endif
   {
      *s = ' ' ;
      s++;
   }
   *s = '\0' ;
}



/*****************************************************************************
** 8 Bit Timer2 initialisieren
**
** Ziel: genau alle 10 Millisekunden einen Interrupt erzeugen
*/
void timer2_init( void )
{
   clock_stopp = intervall * 100;
   clock_s.tim2ovf=0;

   TCCR2B |= (1 << FOC2A )+ (1<< CS22)+ (1<< CS21)+ (1<< CS20);   // Force Output Compare for Channel A
   TCNT2  = 0;                // reset
   TIMSK2 = (1 << OCIE2A );   // enable compare match interrupt
   TCCR2A |= + (1<< WGM21);   // CTC
#if F_CPU == 14745600
   OCR2A  = 143;              // compare match bei 143 + 1 = 144 Takte
#endif
#if F_CPU == 18432000
   OCR2A  = 179;              // compare match bei 179 + 1 = 180 Takte
#endif
}



/*****************************************************************************
*  8 Bit TIMER2 Compare Match 10 msek
*/
ISR ( TIMER2_COMPA_vect )
{
   clock_s.tim2ovf++;                    // timer 2 overflow erkannt +1

   if ( s1_toggle == 1  )        // Frequenz Counter ??
   {
      clock_sync++;
      if ( clock_sync >= clock_stopp )  // 1, 2, 4, oder 10 Sekunden ??
      {
         t0cnt = TCNT0;         // save t0 counter
         TCNT0 = 0;
         t1cnt = TCNT1;         // save t1 counter
         TCNT1 = 0;

         t0ovs = t0over;        // save overflow
         t0over = 0;

         t1ovs = t1over;        // save overflow
         t1over = 0;

         t1vtm  = zmode;        // Vorteiler letzte Messung
         fflag  = 1;            // signal display Messung
         clock_sync = 0;
         if ( pmode == 1 )
         {
            zmode = 1 ;         // vorteiler
            PORTD &= ~BIT6;     // Vorteiler einschalten
         }
         else
         {
            zmode = 0 ;         // vorteiler aus
            PORTD |= BIT6;      // ohne Vorteiler
         }
      }
   }
}



/*****************************************************************************
** Start Frequenz Messung
** Timer0 wird als zaehler benutzt.
** PD4 Port wird als T0 benutzt Spezial Schaltung
** PD6 steuert invertiert den externen Vorteiler
*/
void start_frequ_messung(void)
{
   if ( pmode == 1 )
   {
      zmode = 1 ;        // externer vorteiler
      PORTD &= ~BIT6;    // Vorteiler einschalten (invertiert)
   }
   else
   {
      zmode = 0 ;        // externer vorteiler aus
      PORTD |= BIT6;     // ohne Vorteiler
   }
   lcd_beleuchtung( 4 ); // 100% Licht
   lcd_init(0);          // Timer0 pwm aus 
   
   cli();                // disable Interrupt
   
   t0over = 0;
   t1over = 0;
   TCNT0  = 0;
   TCNT1  = 0;
   
   TCCR0B |= 0x06 ;      // external Clock an PIN T0 PD4, falling edge
   TCCR1B |= 0x07 ;      // external Clock an PIN T1 PD5, rising edge
   TIMSK0 |= (1<<TOIE0); // timer0 overflow int zulassen
   TIMSK1 |= (1<<TOIE1); // timer1 overflow int zulassen
   clock_sync = 0;       // setze beim naechsten T2 Overflow T1 auf 0
   clock_stopp = intervall * 100;
   sei();                // enable interrupt
}



/*****************************************************************************
** Stop Frequenz Messung
*/
void stop_frequ_messung(void)
{
   TCCR0B &= ~0x07 ;        // stop Timer 0
   TCCR1B &= ~0x07 ;        // stop Timer 1
   TIMSK0  &= ~(1<<TOIE0);  // timer0 overflow sperren
   TIMSK1  &= ~(1<<TOIE1);  // timer1 overflow sperren
   clock_sync = 0;
   lcd_init(1);             // Timer0 pwm ein
   lcd_beleuchtung( backlight ); // 100% Licht   
}



/*****************************************************************************
*  8 Bit TIMER0 Overflow, fuer die Pulsweiten Messung
*/
ISR ( TIMER0_OVF_vect )
{
   t0over++;
}



/*****************************************************************************
*  16 Bit TIMER1 Overflow, fuer die Frequenz Messung
*/
ISR ( TIMER1_OVF_vect )
{
   t1over++;
}



/*****************************************************************************
** Schalter Abfrage PORTD
** funktionieren nur wenn Aufruf alle 10 msek
*/
unsigned char test_switch_D( unsigned char i )
{
   unsigned char bit;

   bit = al_bit[i];           // Bit holen

   if ( !(PIND & bit) )       // pressed = 0 ??
   {
      if ( !(PIND & bit) && al_cc[i] < 128 )
      {
         if ( al_cc[i]++ > 3 )
         {
            al_cc[i] = 128;    // pressed
            return 1;
         }
      }
   }
   else
   {
      if ( al_cc[i] >= 128 )
      {
         if ( PIND & bit )
         {
            if ( al_cc[i]++ > 131 )
            {
               al_cc[i] = 0;  // no pressed
               return 2;
            }
         }
      }
   }
   return 0;
}



/*****************************************************************************
** Schalter Abfrage PORTB
** funktionieren nur wenn Aufruf alle 10 msek
*/
unsigned char test_switch_B( unsigned char i )
{
   unsigned char bit;

   bit = al_bit[i];           // Bit holen

   if ( !(PINB & bit) )       // pressed = 0 ??
   {
      if ( !(PINB & bit) && al_cc[i] < 128 )
      {
         if ( al_cc[i]++ > 3 )
         {
            al_cc[i] = 128;    // pressed
            return 1;
         }
      }
   }
   else
   {
      if ( al_cc[i] >= 128 )
      {
         if ( PINB & bit )
         {
            if ( al_cc[i]++ > 131 )
            {
               al_cc[i] = 0;  // no pressed
               return 2;
            }
         }
      }
   }
   return 0;
}
