Subversion Repositories Projects

Rev

Blame | Last modification | View Log | RSS feed


/****************************************************************/
/*                                                                                                                              */
/*                               NG-Video 5,8GHz                                                        */
/*                                                                                                                              */
/*                              Copyright (C) 2011 - gebad                                              */
/*                                                                                                                              */
/*  This code is distributed under the GNU Public License               */
/*      which can be found at http://www.gnu.org/licenses/gpl.txt       */
/*                                                                                                                              */
/****************************************************************/

#include <util/delay.h>

#include "config.h"
#include "ngvideo.h"
#include "keys.h"
#include "menue.h"
#include "servo.h"
#include "messages.c"

typedef uint8_t scr_menu_t[SCROLL_MAIN_MAX + 3]; // einmal, da Index mit 0 beginnt plus Vergrößerung für 2 zusätzlich eingeblendete Punkte
uint8_t m_pkt;          // um bei Rücksprung auf ursprünglichen Arrayeintrag(Menüpunkt) zeigen
uint8_t servo_nr;       // zwischen Servo 1 und 2 wird nur mit global servo_nr unterschieden

COMMAND_STRUCTUR COMMAND_TABELLE[] = // Befehls-Tabelle
{
  {"0",         Menu_Main},
  {"01",        Menu_AV_Source},
  {"02",        Menu_RX_Channel},
  {"03",        Menu_RSSI_Calibr},
  {"031",       Menu_RSSI_min},
  {"032",       Menu_RSSI_max},
  {"04",        Menu_Language},
  {"05",        Menu_Servo_Calibr},
  {"051",       Menu_Servo_Steps},
  {"052",       Menu_Servo1},           // zwischen Servo 1 und 2 wird danach
  {"0521",      Menu_Servo1_rev},       // mit global servo_nr unterschieden
  {"0522",      Menu_Servo1_left},     
  {"0523",      Menu_Servo1_right},
  {"0524",      Menu_Servo1_middle},
  {"053",       Menu_Servo2},
  {"0531",      Menu_Servo2_rev},
  {"0532",      Menu_Servo2_left},
  {"0533",      Menu_Servo2_right},
  {"0534",      Menu_Servo2_middle},
  {"06",        Menu_lcd},
  {"061",       Menu_lcd_Contrast},
  {"062",       Menu_lcd_Backgr_Light},
  {"07",        Menu_Battery},
  {"071",       Menu_Low_U_Setup},
  {"072",       Menu_U_Offset},
  {"08",        Menu_Tracking_Ant},
  {"09",        Menu_Tracking_Option},  // wird nur bei Tracking RSSI oder GPS eingeblendet - SCROLL_MAIN_MAX wird geändert
  {"0:",        Menu_GPS_Display},      // wird nur bei Tracking GPS eingeblendet           - SCROLL_MAIN_MAX wird geändert
  {"0:1",       Menu_GPS_Display_FLAG}, // nach '9' (0x39) folgt ':' (0x3a)
  {"0:2",       Menu_GPS_Display_FLAG},  
  {"0:3",       Menu_GPS_Display_FLAG},  
  {NULL,NULL}
};


uint32_t Change_Value(uint32_t val, uint32_t min_val, uint32_t max_val, uint8_t pos, uint8_t fu_index, uint8_t vrepeat);

void Displ_AV_Source(uint32_t  q);
void Displ_Channels(uint32_t  k);
void Displ_Set_Contrast(uint32_t val);
void Displ_Backgr_Light(uint32_t val);
void Displ_U_2Nk(uint32_t u);
void Displ_Off_On(uint32_t val);
void Displ_Language(uint32_t q);
void DISPL_Servo_Steps(uint32_t val);
void Displ_Servo_Min(uint32_t val);
void Displ_Servo_Max(uint32_t val);
void Displ_Servo_Mid(uint32_t val);
void Displ_Format_Int(uint32_t val);
void Displ_sel_Tracking(uint32_t q);
void Displ_track_TX(uint32_t q);
void Displ_Baudrate(uint32_t q);
typedef void (*Displ_Ptr_Fnct)( uint32_t );
Displ_Ptr_Fnct Displ_Fnct[] = {Displ_U_2Nk, Displ_Set_Contrast, Displ_Backgr_Light, Displ_Channels, Displ_AV_Source, \
                               Displ_Off_On, Displ_Language, DISPL_Servo_Steps, Displ_Servo_Min, Displ_Servo_Max, \
                                                           Displ_Servo_Mid, Displ_Format_Int, Displ_sel_Tracking, Displ_track_TX, Displ_Baudrate};


/**************************************************************/
/*                                                                                                                        */
/*                    Steuerung der Menüs                                         */
/*                                                                                                                        */
/**************************************************************/

/************************************************************************************/
/*  sucht nach übergebenen String in der Kommandotabelle und springt zum daneben        */
/*  stehenden Menü-Programm                                                                                                                     */
/*      Parameter:                                                                                                                                              */
/*  char *string_pointer        :zu suchender String in Kommandotabelle                                 */
/*                                                                                                                                                                      */
/************************************************************************************/
void Jump_Menu(char *string_pointer)
{
  //Stringzeiger;
  char *string_pointer_tmp;
  unsigned char menu_index = 0;

  if (strlen(string_pointer) > 0)
  {
    string_pointer_tmp = strsep(&string_pointer,",");
    //Kommando in Tabelle suchen
    while(strcasecmp(COMMAND_TABELLE[menu_index].menu_nr,string_pointer_tmp))
    {
      //Abruch Whileschleife und Unterprogramm verlassen
      if (COMMAND_TABELLE[++menu_index].menu_nr == 0);
    }
    COMMAND_TABELLE[menu_index].fp();   //Kommando ausführen
  }
}

/************************************************************************************/
/*                                                                                                                                                                      */
/*    Unterprogramm von Scroll_Menu(...) stellt Menüpunkte dar                                          */
/*      Parameter:                                                                                                                                              */
/*      scr_menu_t scr_menu      : Array mit Strings der Menüanzeige                                            */
/*      uint8_t    scr_idx   : ausgewählter Menüpunkt                                                                   */
/*      uint8_t    scroll_max: scrollen bis Wert                                                                                */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Scroll_Menu(scr_menu_t scr_menu, uint8_t scr_idx, uint8_t scroll_max)
{
  uint8_t i;
  const uint8_t p = 2; // LCD Beginn x-Position
 
  if (scr_idx > 0) scr_idx--; else scr_idx = scroll_max;
  for (i = 0; i < LCD_LINES; i++) {
    lcdGotoXY(p, i);
        lcdPuts(Msg(scr_menu[scr_idx]));
        // ab Stringende bis zum Zeilenende löschen; LCD löschen flackert sonst zu sehr
        for (int8_t n = LCD_COLS - strlen(Msg(scr_menu[scr_idx])) - p; n > 0; n--)
          lcdPutc(' ');
        if (scr_idx < scroll_max) scr_idx++; else scr_idx = 0;
  }
}

/************************************************************************************/
/*                                                                                                                                                                      */
/*    scrollt Menü über Mehrzeilige LCD                                                                                         */
/*                                                                                                                                                                      */
/*      Taste<Enter> lang springt in Hauptanzeige, kurz geht in den angewälten Menüpunkt*/
/*      Taste<+>    eine Zeile nach oben                                                                                                */
/*  Taste<->    eine Zeile nach unten                                                                                           */
/*      Parameter:                                                                                                                                              */
/*      scr_menu_t scr_menu      : Array mit Strings der Menüanzeige                                            */
/*      uint8_t    scroll_max: scrollen bis Wert                                                                                */
/*      uint8_t    scr_idx       : Index für array von Displ_Scroll_Menu(...)                           */
/*                                                                                                                                                                      */
/************************************************************************************/
//void Scroll_Menu(scr_menu_t scr_menu, uint8_t scroll_max, uint8_t scr_idx, char *str)
void Scroll_Menu(scr_menu_t scr_menu, uint8_t scroll_max, uint8_t scr_idx)
{ uint8_t l;
  uint8_t end = 1;      // false

  // pmenu[1] == '\0' entspricht <wenn Hauptmenue>, da jetzt nur noch Servo x für Scrollemenue (rev,min,max,mid)
  if ((pmenu[1] == '\0') && ((tracking == TRACKING_RSSI) || (tracking == TRACKING_GPS) || (tracking == TRACKING_MKCOCKPIT))) {
    ++scroll_max;
    if (tracking == TRACKING_RSSI) scr_menu[scroll_max] = MSG_TRACK_SERVO_HYTERESE;
    if (tracking == TRACKING_GPS) {
      scr_menu[scroll_max] = MSG_TRACK_TX_OSD_DATA;
          ++scroll_max; // zusätzliche Anzeige zu GPS
        }
    if (tracking == TRACKING_MKCOCKPIT) scr_menu[scroll_max] = MSG_COM;
  }
  lcdClear();
  lcdGotoXY(0, 1);
  lcdPutc(MARKER_SELECT);    // '>>'
  Displ_Scroll_Menu(scr_menu, scr_idx, scroll_max);
  // bis Menueeingabe bestätigt oder zum vorherigen Menue
  while( !Get_Key_Short( 1<<SW_ENTER ) && end)
  {
    // >> Menueauswahl nach oben
        if( Get_Key_Press( 1<<SW_PLUS ) || Get_Key_Rpt( 1<<SW_PLUS ))
        {
      if (scr_idx > 0) scr_idx--; else scr_idx = scroll_max;
          Displ_Scroll_Menu(scr_menu, scr_idx, scroll_max);
        }  
    // >> Menueauswahl nach unten
    if( Get_Key_Press( 1<<SW_MINUS ) || Get_Key_Rpt( 1<<SW_MINUS ))
        {
          if (scr_idx < scroll_max) scr_idx++; else scr_idx = 0;
          Displ_Scroll_Menu(scr_menu, scr_idx, scroll_max);
        }
        // direkt in das Hauptprogramm
        if (Get_Key_Long( 1<<SW_ENTER )) end = 0;
        Tasks_unvisible();
        // falls Akku leer ==> Menü verlassen und Anzeige __ACCU_LOW
        U_Messen_cmp(DISABLE_BTIMER);
        if (bat_low == 0) end = 0;
  }
  lcdClear();
  if (end) {
    l = strlen(pmenu);
    if (scr_idx > 0) {
      m_pkt = 1;                                // 0 wäre "zurück", so aber ins Untermenü immer erster Menüpunkt
      pmenu[l] = scr_idx + '0'; // nächsten MenueIndex anhängen 1 oder 2 oder ...
      pmenu[l + 1] ='\0';
          Beep(BEEPENTER);
        }
        else {
          l--;
          m_pkt = pmenu[l] - '0';               // um bei Rücksprung auf ursprünglichen Arrayeintrag(Menüpunkt) zeigen
          pmenu[l] ='\0';  // auf letztes Zeichen Stringende schreiben
          if (l == 0) Displ_Main_Disp();
        }
  }
  else {
    pmenu[0] = '\0';
        Displ_Main_Disp();
  }
}

/************************************************************************************/
/*                                                                                                                                                                      */
/*                      Abfrage Short- oder Long-Enter                                                          */
/*        verbleibt in Abfrage bis Enter betätigt; Rückgabe => Short-Enter True/False   */
/*                                                                                                                                                                      */
/************************************************************************************/
uint8_t Short_Enter(void)
{ uint8_t ShortEnter = 1;

  // bis Enter
  while( !Get_Key_Short( 1<<SW_ENTER ) && (ShortEnter > 0)) {  
        // direkt in das Hauptprogramm
        if (Get_Key_Long( 1<<SW_ENTER )) {
          ShortEnter = 0;
          pmenu[0] ='\0';
    }
        Tasks_unvisible();
        // falls Akku leer ==> Menü verlassen und Anzeige __ACCU_LOW
        U_Messen_cmp(DISABLE_BTIMER);
        if (bat_low == 0) pmenu[0] ='\0';
  }
  lcdClear();
  if (ShortEnter) Beep(BEEPENTER);
  if (pmenu[0] == '\0') Displ_Main_Disp();
  return(ShortEnter);
}

/************************************************************************************/
/*                                                                                                                                                                      */
/*    Ändern der Werte mit Tasten +,- und Anzeige                                                                       */
/*                      z.B. für U-Offset, Batterie leer Eingabe ...                                            */
/*                                                                                                                                                                      */
/*      Parameter:                                                                                                                                              */
/*      uint32_t val                            :zu ändernter Wert                                                                      */
/*      uint32_t min_val, max_val       :min, max Grenze Wert ändern darf                                       */
/*      uint8_t  posX, posY                     :Darstellung Wert xPos, YPos auf LCD                            */
/*      uint8_t  fu_index                       :Index um Adresse der Display Funktion aufzurufen       */
/*      uint8_t  cycle                          :0 begrenzt Anzeige bei man_val, bzw. max_val           */
/*                                                              :1 springt nach max_val auf min_val und umgedreht       */
/*  uint8_t      vrepeat                        :beschleunigte Repeat-Funktion aus/ein                          */
/*      uint32_t Change_Value_plmi(...) :Rückgabe geänderter Wert                                               */
/*                                                                                                                                                                      */
/************************************************************************************/
uint32_t Change_Value_plmi(uint32_t val, uint32_t min_val, uint32_t max_val, uint8_t posX, uint8_t posY, \
                           uint8_t fu_index, uint8_t cycle, uint8_t vrepeat)
{
  // >> Menueauswahl nach oben
  if( Get_Key_Press( 1<<SW_PLUS ) || Get_Key_Rpt( 1<<SW_PLUS )){
    if (val < max_val) {
      val++;
          Key_Speedup_rpt(vrepeat);     // beschleunigte Repeat-Funktion
        }
        else
          if (cycle) {
        val = min_val;
        }
    lcdGotoXY(posX, posY);              // lcd Position Wert
    Displ_Fnct[fu_index](val);  // geänderten Wert darstellen, je nach Menüpunkt
  }
  // >> Menueauswahl nach unten
  if( Get_Key_Press( 1<<SW_MINUS ) || Get_Key_Rpt( 1<<SW_MINUS )) {
    if (val > min_val) {
      val--;
          Key_Speedup_rpt(vrepeat);     // beschleunigte Repeat-Funktion
        }
        else
          if (cycle) {
        val = max_val;
          }
    lcdGotoXY(posX, posY);              // noch einmal lcd Position, sonst zum Teil + und - gleichzeitig, Anzeige verrutscht
        Displ_Fnct[fu_index](val);      // geänderten Wert darstellen, je nach Menüpunkt
  }
  return(val);
}

/************************************************************************************/
/*                                                                                                                                                                      */
/*    Ändern der Werte mit Tasten +,- repetierend; (long)Entertaste und Anzeige         */
/*                      z.B. für U-Offset, Batterie leer Eingabe ...                                            */
/*                                                                                                                                                                      */
/*      Parameter:                                                                                                                                              */
/*      uint32_t val                            :zu ändernter Wert                                                                      */
/*      uint32_t min_val, max_val       :min, max Grenze Wert ändern darf                                       */
/*      uint8_t  pos                            :Darstellung Wert xPos auf LCD                                          */
/*      uint8_t  fu_index                       :Index um Adresse der Display Funktion aufzurufen       */
/*  uint8_t      vrepeat                        :beschleunigte Repeat-Funktion aus/ein                          */
/*      uint32_t Change_Value(...)      :Rückgabe geänderter Wert                                                       */
/*                                                                                                                                                                      */
/************************************************************************************/
uint32_t Change_Value(uint32_t val, uint32_t min_val, uint32_t max_val, uint8_t pos, uint8_t fu_index, \
                      uint8_t vrepeat)
{ uint8_t l;

  lcdGotoXY(pos, ZLE_VAL);              // Position Wert
  Displ_Fnct[fu_index](val);    // initiale Wertdarstellung, je nach Menüpunkt
  // bis Menueeingabe bestätigt oder zum vorherigen Menue
  while( !Get_Key_Short( 1<<SW_ENTER ) && (strlen(pmenu) > 0))
  {
    val = Change_Value_plmi(val, min_val, max_val, pos, ZLE_VAL, fu_index, 0, vrepeat);
        // direkt in das Hauptprogramm zurück
        if (Get_Key_Long( 1<<SW_ENTER )) pmenu[0] ='\0';
        Tasks_unvisible();
        // falls Akku leer ==> Menü verlassen und Anzeige MSG_ACCU_LOW
        U_Messen_cmp(DISABLE_BTIMER);
        if (bat_low == 0) pmenu[0] ='\0';
  }
  lcdClear();
  l = strlen(pmenu);
  if (l > 0) {
    l--;
        m_pkt = pmenu[l] - '0'; // um bei Rücksprung auf ursprünglichen Arrayeintrag(Menüpunkt) zeigen
        pmenu[l] ='\0';                 // auf letztes Zeichen Stringende schreiben
  }
  else
    Displ_Main_Disp();
  return(val);
}



/**************************************************************/
/*                                                                                                                        */
/*             LCD-Darstellungen der Menüs                                        */
/*      Zur Unterstützung der Auswahl werden einige Einstellungen */
/*      sofort ausgeführt. Z.B.: Kontrast, Servo-Endausschlag     */
/*                                                                                                                        */
/**************************************************************/

/************************************************************************************/
/*  stellt eine String mittig auf Display dar                                                                           */
/*      Parameter:                                                                                                                                              */
/*  char        *str    : darzustellende Zeichenkette                                                                   */
/*      uint8_t zle             : Display-Zeile                                                                                                 */
/*                                                                                                                                                                      */
/************************************************************************************/
void Disp_Str_mid(char *str, uint8_t zle)
{ int8_t x;

  lcdGotoXY(0,zle);
  for (x = 0; x < LCD_COLS; x++) lcdPutc(' '); // Zeile löschen
  x = (LCD_COLS - strlen(str))/2;  // Array-String mittig schreiben
  lcdGotoXY(x,zle);
  lcdPuts(str);
}

/************************************************************************************/
/*  zeigt Menü-  * Überschrift *  auf erste Zeile mittig auf Display an                         */
/*      Parameter:                                                                                                                                              */
/*  uint8_t message     : index (MSG_) der darzustellenden Zeichenkette                                 */
/*                                                                                                                                                                      */
/************************************************************************************/
void Disp_Title(uint8_t message)
{ uint8_t l;
  uint8_t x = 0;

  l = strlen(Msg(message));
  if ( LCD_COLS > l) x = (LCD_COLS - l)/2;
  if (x > 1) {
    lcdGotoXY(x - 2, 0);
    lcdPuts("* ");
        lcdPuts(Msg(message));
    lcdPutc(' ');
  }
  else {
    lcdGotoXY(0, 0);
    lcdPutc('*');
    lcdGotoXY(x, 0);
        lcdPuts(Msg(message));
        lcdGotoXY(LCD_COLS - 1, 0);
  }
  lcdPutc('*');
}

/************************************************************************************/
/*        zeigt bei Programmstart Firmware- und DOGM-Version auf Display an                     */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Version(void)
{
  lcdGotoXY(0, 0);
  lcdPuts(Msg(MSG_VERSION1));
  if (dogm_vers == DOGM3V)
    lcdPuts(Msg(MSG_UHW33V));
  else
    lcdPuts(Msg(MSG_UHW5V));
  lcdPuts(Msg(MSG_VERSION2));
  for ( uint8_t i=0; i<=30;i++)
    _delay_ms(100);
  lcdClear();
}

/************************************************************************************/
/*  zeigt auszuwählenden/-gewählten Kanal und Frequenz auf Display an                           */
/*      Parameter:                                                                                                                                              */
/*  uint32_t k                  :Index anzuzeigender Wert = Kanal + 0x30 als Char,                      */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Channels(uint32_t k)
{ char *channels[] =    {"5740", "5760","5780", "5800", "5820", "5840", "5860"};

  lcdPutc(k+0x30);
  lcdPuts(": ");
  lcdPuts(channels[k-1]);
  lcdPuts("MHz");
}

/************************************************************************************/
/*  zeigt Source AV1, AV2 oder Diversity zur Auswahl auf Display an                                     */
/*      Parameter:                                                                                                                                              */
/*  uint32_t q                  :Index anzuzeigender Wert,                                                                      */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_AV_Source(uint32_t q)
{ uint8_t av_src_table[] = {MSG_AV1, MSG_AV2, MSG_DIVERSITY};

  Disp_Str_mid(Msg(av_src_table[q]), ZLE_VAL);
}

/************************************************************************************/
/*  zeigt Tracking-Varianten zur Auswahl auf Display an                                                         */
/*      Parameter:                                                                                                                                              */
/*  uint32_t q                  :Index anzuzeigender Wert,                                                                      */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_sel_Tracking(uint32_t q)
{ uint8_t track_sel_table[] =    {MSG_OFF, MSG_TRACK_RSSI, MSG_TRACK_GPS, MSG_TRACK_MKCOCKPIT};

  Disp_Str_mid(Msg(track_sel_table[q]), ZLE_VAL);
}

/************************************************************************************/
/*  zeigt Senden der OSD-Daten Anforderung zur Auswahl auf Display an                           */
/*      Parameter:                                                                                                                                              */
/*  uint32_t q                  :Index anzuzeigender Wert,                                                                      */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_track_TX(uint32_t q)
{ uint8_t track_TX_table[] =    {MSG_OFF, MSG_TRACK_TX_ON};

  Disp_Str_mid(Msg(track_TX_table[q]), ZLE_VAL);
}

/************************************************************************************/
/*  zeigt einen max. 3-stelligen Integerwert auf Display an                                                     */
/*      Parameter:                                                                                                                                              */
/*  uint32_t val                :anzuzeigender Wert,                                                                            */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Format_Int(uint32_t val)
{ char s[4];
 
  if (val < 100) lcdPutc(' ');
  if (val < 10) lcdPutc(' ');
  utoa(val ,s ,10 );
  lcdPuts(s);
}

/************************************************************************************/
/*  zeigt den Kontrastwert auf Display an mit sofortiger Änderung                                       */
/*      Parameter:                                                                                                                                              */
/*  uint32_t val                :anzuzeigender Wert,                                                                            */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Set_Contrast(uint32_t val)
{
  Displ_Format_Int(val);
  lcdContrast(dogm_vers, val);
}

/************************************************************************************/
/*  zeigt die Zeit zur Abschaltung der LCD-Hintergrundbeleuchtung an                            */
/*      Parameter:                                                                                                                                              */
/*  uint32_t val                :anzuzeigender Wert,                                                                            */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Backgr_Light(uint32_t val)
{ char str[5];
  uint8_t l;
 
  l = strlen(Msg(MSG_LIGHT));   // etwas Aufwand um Zeilenende sauber zu löschen
  switch(val) {
    case BACKGR_LIGHT_MIN : l += strlen(Msg(MSG_LIGHT_OFF));
                                                        lcdPuts(Msg(MSG_LIGHT_OFF));
                                                        break;
        case BACKGR_LIGHT_MAX : l += strlen(Msg(MSG_LIGHT_ON));
                                                        lcdPuts(Msg(MSG_LIGHT_ON));
                                                        break;
        default :                               itoa (val * 10, str, 10);
                                                        lcdPutc(' ');
                                                        lcdPuts(str);
                                                        lcdPuts(Msg(MSG_SEC));
                                                        l += 1 + strlen(str) + strlen(Msg(MSG_SEC));
  }
  l = LCD_COLS - l;
  for (uint8_t x = 0; x < l; x++) lcdPutc(' '); // Zeilenende löschen
}

/************************************************************************************/
/*  zeigt ein oder aus zur Auswahl auf Display an                                                                       */
/*      Parameter:                                                                                                                                              */
/*  uint32_t val                :0 = aus oder 1 = ein,                                                                          */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Off_On(uint32_t val)
{
  if (val == 0) lcdPuts(Msg(MSG_OFF)); else lcdPuts(Msg(MSG_ON));
}

/************************************************************************************/
/*  zeigt Servoschritte zur Auswahl auf Display an                                                                      */
/*      Parameter:                                                                                                                                              */
/*  uint32_t val                :0 = 255 oder 1 = 1023,                                                                         */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void DISPL_Servo_Steps(uint32_t val)
{ uint8_t servo_step_table[] =  {MSG_STEPS_255, MSG_STEPS_1023};

  Disp_Str_mid(Msg(servo_step_table[val]), ZLE_VAL);
}

/************************************************************************************/
/*  zeigt Servo-Anschlagposition links auf Display an                                                           */
/*  mit sofortiger Wirkung auf Servo                                                                                            */
/*      Parameter:                                                                                                                                              */
/*  uint32_t val                :anzuzeigender Wert,                                                                            */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Servo_Min(uint32_t val)
{ uint16_t steps = 0;

  Displ_Format_Int(val);
  servoSet_min(servo_nr, val);                          // Wert setzen damit nachfolgend die
  if (servo[servo_nr].rev) steps = ServoSteps();
  servoSetPosition(servo_nr, steps);            // Änderung direkt am Servo sichtbar ist
}

/************************************************************************************/
/*  zeigt Servo-Anschlagposition rechts auf Display an                                                          */
/*  mit sofortiger Wirkung auf Servo                                                                                            */
/*      Parameter:                                                                                                                                              */
/*  uint32_t val                :anzuzeigender Wert,                                                                            */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Servo_Max(uint32_t val)
{ uint16_t steps = ServoSteps();

  Displ_Format_Int(val);
  servoSet_max(servo_nr, val);                          // Wert setzen damit nachfolgend die
  if (servo[servo_nr].rev) steps = 0;
  servoSetPosition(servo_nr, steps);            // Änderung direkt am Servo sichtbar ist
}

/************************************************************************************/
/*  zeigt Servo-Anschlagposition Mitte auf Display an                                                           */
/*  mit sofortiger Wirkung auf Servo                                                                                            */
/*      Parameter:                                                                                                                                              */
/*  uint32_t val                :anzuzeigender Wert,                                                                            */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Servo_Mid(uint32_t val)
{ char s[6];
  int16_t mid_val;
 
  mid_val = val - ServoSteps()/2;
  if (abs(mid_val) < 10) lcdPutc(' ');           // einstellige Ausgabe eins nach rechts rücken
  if (mid_val > -1) lcdPutc(' ');                        // ohne Vorzeichen Ausgabe eins nach rechts rücken
  itoa(mid_val ,s ,10 );
  lcdPuts(s);
  lcdPutc(' ');                                                          // nach Werten > 99 letzte 0 wieder löschen
  servoSet_mid(servo_nr, val);                           // Wert setzen damit nachfolgend die
  servoSetPosition(servo_nr, ServoSteps()/2);// Änderung direkt am Servo sichtbar ist
}

/************************************************************************************/
/*  zeigt Baudrate für COM bei MKCockpit zur Auswahl auf Display an                                     */
/*      Parameter:                                                                                                                                              */
/*  uint32_t q                  :Index anzuzeigender Wert,                                                                      */
/*                                               unint32_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Baudrate(uint32_t q)
{ char str[7];

  ltoa(baud[q], str, 10);
  Disp_Str_mid(str, ZLE_VAL);
}

/************************************************************************************/
/*  zeigt den Marker in Hauptdarstellung auf selektierten RX an                                         */
/*  d Diversity, << fester RX                                                                                                           */
/*      Parameter:                                                                                                                                              */
/*  uint8_t p           :x-Position des Markers                                                                                 */
/*  uint8_t marker      :Markerzeichen z.B.:'' oder 'd' oder 's'                                                */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_AV_Mark(uint8_t p, char marker)
{
  if (p < 2) {
    lcdGotoXY(15,2 - p);        // da p immer neue Position 0 oder 1
    lcdPutc(' ');                       // bisherigen AVx-, Diversity-Marker löschen
    lcdGotoXY(15,p + 1);        // an neuer Positon
    lcdPutc(marker);            // übergebenes Markerzeichen darstellen
   }
   else { // falls beim Einschalten Diversity auf aktiv, keine Marker
    lcdGotoXY(15,1);
    lcdPutc(' ');
    lcdGotoXY(15,2);
    lcdPutc(' ');
   }
}

/************************************************************************************/
/*                      Hauptanzeige unter Berücksichtigung von VBat                                            */
/*                                                                                                                                                                      */
/************************************************************************************/
void Displ_Main_Disp(void)
{ char marker;

  lcdClear();
  if (bat_low != 0) {
    lcdClear();
    Displ_Channels(channel);
    lcdGotoXY(LCD_COLS - 1, 0);
    lcdPuts("V\n1\n2");
    if (av_source < DIVERSITY)
          marker = MARKER_AV;   // wird nur bei gesetzten Diversity überschrieben
        else
          marker = MARKER_RSSI; // nur Schönheit, damit man sofort Umschaltung sieht
        Displ_AV_Mark(sw_avx, marker);
    Displ_VBat(); // muss zuletzt stehen
  }
  else {
    Disp_Str_mid(Msg(MSG_ACCU_LOW), 0);
  }
}



/**************************************************************/
/*                                                                                                                        */
/*                          Menüs                                                         */
/*                                                                                                                        */
/**************************************************************/

/**************************/
/*                                                */
/*         Haupmenü               */
/*                                                */
/**************************/
void Menu_Main(void)
{ scr_menu_t scr_main_menu = {MSG_RETURN, MSG_AV_SOURCE, MSG_RX_CHANNEL, MSG_RSSI_CALIBR, MSG_LANGUAGE, MSG_SERVO_CALIBR, \
                                                          MSG_LCD , MSG_BATTERY, MSG_TRACKING, 0, MSG_GPS_DISPLAY};

  strcpy(pmenu, "0");
  Scroll_Menu(scr_main_menu, SCROLL_MAIN_MAX, m_pkt); // pmenu global
  Jump_Menu(pmenu); //gewähltes Untermenü anspringen oder nur Return
}

/**************************/
/*                                                */
/*        AV-Quelle               */
/*                                                */
/**************************/
void Menu_AV_Source(void)
{ char marker;
  uint32_t eep_val;

  Disp_Title(MSG_AV_SOURCE);
  eep_val = Change_Value(av_source, AV_SOURCE_MIN, AV_SOURCE_MAX, 3, IDX_DISPL_AV_SOURCE, C_REPEAT); // pmenu global
  if (eep_val != av_source) {
    cli();
        av_source = eep_val;
        eeprom_write_byte(&ep_av_source, av_source);
        Double_Beep(DBEEPWR, DBEEPWRP);
        sw_avx = Set_AV_Source(av_source);
    if (pmenu[0] == '\0') {             // sonst ist AV-Source marker im Hauptdisplay nicht aktuallisiert
      if (av_source < DIVERSITY)
            marker = MARKER_AV;                 // wird nur bei gesetzten Diversity überschrieben
          else
            marker = MARKER_RSSI;               // nur Schönheit, damit man sofort Umschaltung sieht
          Displ_AV_Mark(sw_avx, marker);// da erst jetzt die Variable für main_display geändert ist!
        }
        sei();
  }
  Jump_Menu(pmenu);
}

/**************************/
/*                                                */
/*        Kanal                   */
/*                                                */
/**************************/
void Menu_RX_Channel(void)
{ uint32_t eep_val;

  Disp_Title(MSG_RX_CHANNEL);
  eep_val = Change_Value(channel, CHANNEL_MIN, CHANNEL_MAX, 3, IDX_DISPL_CHANNEL, C_REPEAT);  // pmenu global
  if ((eep_val != channel) || (eep_val != ch_stored)) { // oder Channel wurde im Hauptdisplay geändert
    channel = eep_val;
        ch_stored = eep_val;
        eeprom_write_byte(&ep_channel, channel);
        Double_Beep(DBEEPWR, DBEEPWRP);
        Set_Channel(channel);
    if (pmenu[0] == '\0') {     // sonst ist channel im Hauptdisplay nicht aktuallisiert
      lcdGotoXY(0,0);
      Displ_Channels(channel);  // da erst jetzt die Variable für main_display geändert ist!
    }
  }
  Jump_Menu(pmenu);
}

/**************************/
/*                                                */
/*        RSSI                    */
/*                                                */
/**************************/
void Menu_RSSI_Calibr(void)
{ uint8_t scr_sub_menu[3]  = {MSG_RETURN, MSG_RSSI_MIN, MSG_RSSI_MAX};

  Scroll_Menu(scr_sub_menu, 2, m_pkt); // pmenu global
  Jump_Menu(pmenu);
}

void Menu_RSSI_min(void)
{ char str[20];

  Disp_Title(MSG_RSSI_MIN);
  strcpy(str, Msg(MSG_TX));
  strcat(str, Msg(MSG_TX_OFF));
  Disp_Str_mid(str, 1);
  Disp_Str_mid(Msg(MSG_CONTINUE), 2);
  if (Short_Enter()) {                  // pmenu global
    RSSI_Min_Calibrate(pudbm);
        pmenu[0] = '\0';                        // zur Hauptdarstellung
        Displ_Main_Disp();                      // da erst jetzt die Variable für main_display geändert ist!
  }
  else
    Jump_Menu(pmenu);
}

void Menu_RSSI_max(void)
{ char str[20];

  Disp_Title(MSG_RSSI_MAX);
  strcpy(str, Msg(MSG_TX));
  strcat(str, Msg(MSG_TX_ON));
  Disp_Str_mid(str, 1);
  Disp_Str_mid(Msg(MSG_CONTINUE), 2);
  if (Short_Enter()) {                  // pmenu global
    RSSI_Max_Calibrate(pudbm);
        pmenu[0] = '\0';                        // zur Hauptdarstellung
        Displ_Main_Disp();                      // da erst jetzt die Variable für main_display geändert ist!
  }
  else
    Jump_Menu(pmenu);
}

/**************************/
/*                                                */
/*        Sprache                 */
/*                                                */
/**************************/
void Displ_Language(uint32_t i)
{ uint8_t lanuage_table[3] = {MSG_GERMAN, MSG_ENGLISH, MSG_FRENCH};

  Disp_Str_mid(Msg(lanuage_table[i]), ZLE_VAL);
}

void Menu_Language(void)
{ uint32_t eep_val;

  Disp_Title(MSG_LANGUAGE);
  eep_val = Change_Value(language, GERMAN, LAST_LANG, 3, IDX_DISPL_LANGUAGE, C_REPEAT); // pmenu global
  language = eeprom_read_byte(&ep_language); // damit bei Erstinbetriebnahme Sprache gespeichert wird NO_LANGUAGE
  if (eep_val != language) {
        language = eep_val;
        eeprom_write_byte(&ep_language, language);
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
  Jump_Menu(pmenu);
}

/**************************/
/*                                                */
/*        Servos                  */
/*                                                */
/**************************/
void Menu_Servo_Calibr(void)
{ uint8_t scr_sub_menu[4] = {MSG_RETURN, MSG_SERVO_STEPS, MSG_SERVO1, MSG_SERVO2};

  Scroll_Menu(scr_sub_menu, 3, m_pkt); // pmenu global
  Jump_Menu(pmenu);
}

void Servo_NewValues(uint8_t idx_presc)
{
  for (uint8_t i = 0; i < SERVO_NUM_CHANNELS; i++) {
        if (idx_presc == STEPS_255) {   // Werte umrechnen für Prescaler = 256
          servo[i].min /= 4;
          servo[i].max /= 4;
          servo[i].mid /= 4;
        }
        else {                                                  // Werte umrechnen für Prescaler = 64
          servo[i].min *= 4;
          servo[i].max *= 4;
          servo[i].mid *= 4;
        }
        servoSet_min(i, servo[i].min);
        servoSet_max(i, servo[i].max);
        servoSet_mid(i, servo[i].mid);
        eeprom_write_block(&servo[i],&ep_servo[i],sizeof(servo_t));
  }
  // Vorberechnung von ServoChannels[channel].duty
  servoSetDefaultPos(); // Ausgangsstellung beider Servos
}

void Menu_Servo_Steps(void)
{ uint32_t eep_val;

  Disp_Title(MSG_SERVO_STEPS);
  lcdGotoXY(8, ZLE_VAL);
  eep_val = Change_Value(sIdxSteps, STEPS_255, STEPS_1023, 5, IDX_DISPL_SERVO_STEPS, C_REPEAT); // pmenu global
  if (eep_val != sIdxSteps) {
        cli();
    sIdxSteps = eep_val;
        eeprom_write_byte(&ep_sIdxSteps, sIdxSteps);
        Servo_NewValues(sIdxSteps);  // hier ist der neue Index anzugeben!
        servoInit();
        sei();
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
  Jump_Menu(pmenu);
}

void Menu_Servo1(void)
{ uint8_t scr_servo_menu[5] = {MSG_RETURN, MSG_SERVO1_REVERSE, MSG_CALIB1_LEFT, MSG_CALIB1_RIGHT, MSG_CALIB1_MIDDLE};
 
  Scroll_Menu(scr_servo_menu, SCROLL_SERVO_MAX, m_pkt); // pmenu global
  servo_nr = 0;
  Jump_Menu(pmenu);
}

void Menu_Servo2(void)
{ uint8_t scr_servo_menu[5] = {MSG_RETURN, MSG_SERVO2_REVERSE, MSG_CALIB2_LEFT, MSG_CALIB2_RIGHT, MSG_CALIB2_MIDDLE};
 
  Scroll_Menu(scr_servo_menu, SCROLL_SERVO_MAX, m_pkt); // pmenu global
  servo_nr = 1;
  Jump_Menu(pmenu);
}

uint8_t Servo_tmp_on(void)
{ uint8_t tmp_tracking = tracking;

  tracking = 0;                                                           // Servopositionierung durch tracking abschalten
  if (tracking == TRACKING_MIN) servoInit(); // falls aus, Servos einschalten
  lcdGotoXY(0, 0);                                                        // lcd Cursor vorpositionieren
  return(tmp_tracking);
}

void Servo_tmp_Original(uint8_t track)
{ uint16_t steps;

  if (servo_nr == SERVO_PAN)
        steps = ServoSteps()/2;                         // PAN auf Mittelstellung
  else
    steps = 0;                                                  // Tilt auf Endausschlag
  servoSetPosition(servo_nr, steps);    // Bei PAN auf ServoSteps/2 und bei Tilt auf 0 oder ServoSteps NICHT!!! reverse beachten
  tracking = track;                                             // ursprünglicher Wert Tracking aus, RSSI oder GPS
  if (tracking == TRACKING_MIN) {
    for (uint8_t i = 0; i < 2; i++)
      _delay_ms(200);                                   // sonst werden Impulse bereits vor erreichen der Servo-default-Stellung abgeschaltet
    servoOff();                                                 // Servos sind nur zum Tracking oder bei Kalibrierung eingeschaltet
  }
  Jump_Menu(pmenu);
}

void Menu_Servo_rev(void)
{ uint32_t eep_val;
  uint8_t tmp_tracking;

  tmp_tracking = Servo_tmp_on();
  eep_val = Change_Value(servo[servo_nr].rev, 0, 1, 6, IDX_DISPL_OFF_ON, C_REPEAT); // pmenu global; reverse gibt es nur 0=off, 1=on
  if (eep_val != servo[servo_nr].rev) {
    servo[servo_nr].rev = eep_val;
        servoSet_rev(servo_nr, eep_val);
        eeprom_write_block(&servo[servo_nr],&ep_servo[servo_nr],sizeof(servo_t));
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
  Servo_tmp_Original(tmp_tracking);
}

void Menu_Servo1_rev(void)
{
  Disp_Title(MSG_SERVO1_REVERSE);
  Menu_Servo_rev();
}

void Menu_Servo2_rev(void)
{
  Disp_Title(MSG_SERVO2_REVERSE);
  Menu_Servo_rev();
}

void Menu_Servo_left(void)
{ uint32_t eep_val;
  uint8_t tmp_tracking;

  tmp_tracking = Servo_tmp_on();
  servoSetPosition(servo_nr, ServoSteps());             // Linkssanschlag um Kalibrierung am Servo zu sehen
  eep_val = Change_Value(servo[servo_nr].max, servo_limit[sIdxSteps][LEFT].min, servo_limit[sIdxSteps][LEFT].max, 6, IDX_DISPL_SERVO_MAX, V_REPEAT); // pmenu global
  if (eep_val != servo[servo_nr].max) {
    servo[servo_nr].max = eep_val;
        eeprom_write_block(&servo[servo_nr],&ep_servo[servo_nr],sizeof(servo_t));
        servoSet_mid(servo_nr, servo[servo_nr].mid);    // Mittelposition muss sich bei Ausschlagsänderung verschieben
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
  Servo_tmp_Original(tmp_tracking);
}

void Menu_Servo1_left(void)
{
  Disp_Title(MSG_CALIB1_LEFT);
  Menu_Servo_left();
}

void Menu_Servo2_left(void)
{
  Disp_Title(MSG_CALIB2_LEFT);
  Menu_Servo_left();
}

void Menu_Servo_right(void)
{ uint32_t eep_val;
  uint8_t tmp_tracking;

  tmp_tracking = Servo_tmp_on();
  servoSetPosition(servo_nr, 0);                                        // Rechtsanschlag um Kalibrierung am Servo zu sehen
  eep_val = Change_Value(servo[servo_nr].min, servo_limit[sIdxSteps][RIGHT].min, servo_limit[sIdxSteps][RIGHT].max, 6, IDX_DISPL_SERVO_MIN, V_REPEAT); // pmenu global
  if (eep_val != servo[servo_nr].min) {
    servo[servo_nr].min = eep_val;
        eeprom_write_block(&servo[servo_nr],&ep_servo[servo_nr],sizeof(servo_t));
        servoSet_mid(servo_nr, servo[servo_nr].mid);    // Mittelposition muss sich bei Ausschlagsänderung verschieben
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
   Servo_tmp_Original(tmp_tracking);
}

void Menu_Servo1_right(void)
{
  Disp_Title(MSG_CALIB1_RIGHT);
  Menu_Servo_right();
}

void Menu_Servo2_right(void)
{
  Disp_Title(MSG_CALIB2_RIGHT);
  Menu_Servo_right();
}

void Menu_Servo_middle(void)
{ uint32_t eep_val;
  uint8_t tmp_tracking;

  tmp_tracking = Servo_tmp_on();
  servoSetPosition(servo_nr, ServoSteps()/2);           // Mittelposition um Kalibrierung am Servo zu sehen
  eep_val = Change_Value(servo[servo_nr].mid, servo_limit[sIdxSteps][MIDDLE].min, servo_limit[sIdxSteps][MIDDLE].max, 6, IDX_DISPL_SERVO_MID, V_REPEAT); // pmenu global
  if (eep_val != servo[servo_nr].mid) {
    servo[servo_nr].mid = eep_val;
        eeprom_write_block(&servo[servo_nr], &ep_servo[servo_nr], sizeof(servo_t));
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
  Servo_tmp_Original(tmp_tracking);
}

void Menu_Servo1_middle(void)
{
  Disp_Title(MSG_CALIB1_MIDDLE);
  Menu_Servo_middle();
}

void Menu_Servo2_middle(void)
{
  Disp_Title(MSG_CALIB2_MIDDLE);
  Menu_Servo_middle();
}

/**************************/
/*                                                */
/*              LCD                       */
/*                                                */
/**************************/
void Menu_lcd(void)
{ uint8_t scr_sub_menu[3] = {MSG_RETURN, MSG_CONTRAST, MSG_BACKGR_LIGHT};

  Scroll_Menu(scr_sub_menu, 2, m_pkt); // pmenu global
  Jump_Menu(pmenu);
}

void Menu_lcd_Contrast(void)
{ uint32_t eep_val;

  Disp_Title(MSG_LCD);
  lcdGotoXY(2, ZLE_VAL);
  lcdPuts(Msg(MSG_CONTRAST));
  lcdPuts(": ");
  eep_val = Change_Value(contrast, CONTRAST_MIN, CONTRAST_MAX, 11, IDX_DISPL_SET_CONTRAST, C_REPEAT); // pmenu global
  if (eep_val != contrast) {
    contrast = eep_val;
        eeprom_write_byte(&ep_contrast, contrast);
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
  Jump_Menu(pmenu);
}

void Menu_lcd_Backgr_Light(void)
{ uint32_t eep_val;

  Disp_Title(MSG_BACKGR_LIGHT);
  lcdGotoXY(0, ZLE_VAL);
  lcdPuts(Msg(MSG_LIGHT));
  eep_val = Change_Value(light_time, BACKGR_LIGHT_MIN, BACKGR_LIGHT_MAX, 6, IDX_DISPL_BACKGR_LIGHT, V_REPEAT); // pmenu global
  if (eep_val != light_time) {
    light_time = eep_val;
        eeprom_write_byte(&ep_light_time, light_time);
        Double_Beep(DBEEPWR, DBEEPWRP);
        if (light_time == BACKGR_LIGHT_MIN) lcdSet_BackgrLight_Off(); // Hintergrundbeleuchtung immer aus ==> sofort schalten
  }
  Jump_Menu(pmenu);
}

/**************************/
/*                                                */
/*        Batterie                */
/*                                                */
/**************************/
void Menu_Battery(void)
{ uint8_t scr_sub_menu[3] = {MSG_RETURN, MSG_U_SETUP, MSG_U_OFFSET};

  Scroll_Menu(scr_sub_menu, 2, m_pkt); // pmenu global
  Jump_Menu(pmenu);
}

void Menu_Low_U_Setup(void)
{ uint32_t eep_val;

  Disp_Title(MSG_U_MIN);
  eep_val = Change_Value(u_min, U_MIN_MIN, U_MIN_MAX, 4, IDX_DISPL_U_2Nk, V_REPEAT); // pmenu global
  if (eep_val != u_min) {
    u_min = eep_val;
        eeprom_write_dword(&ep_u_min, u_min);
        hyst_u_min = u_min;
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
  Jump_Menu(pmenu);
}

void Menu_U_Offset(void)
{ uint32_t eep_val;

  Disp_Title(MSG_U_OFFSET);
  eep_val = Change_Value(u_offset, U_OFFSET_MIN, U_OFFSET_MAX, 4, IDX_DISPL_U_2Nk, V_REPEAT); // pmenu global
  if (eep_val != u_offset) {
    u_offset = eep_val;
        eeprom_write_byte(&ep_u_offset, u_offset);
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
  Jump_Menu(pmenu);
}

/**************************/
/*                                                */
/*  Antennennachführung   */
/*                                                */
/**************************/
void Menu_Tracking_Ant(void)
{ uint32_t eep_val;

  Disp_Title(MSG_TRACKING);
  eep_val = Change_Value(tracking, TRACKING_MIN, TRACKING_MAX, 3, IDX_DISPL_SEL_TRACKING, C_REPEAT); // pmenu global
  if (eep_val != tracking) {
    cli();
        tracking = eep_val;
        sei();
        eeprom_write_byte(&ep_tracking, tracking);
        Double_Beep(DBEEPWR, DBEEPWRP);
    USART_RX_Mode(tracking);    // Unterschied Datenempfang GPS/MKCockpit
        coldstart = 1;
        servoSetDefaultPos();           // Ausgangsstellung beider Servos
    if (tracking > TRACKING_MIN)
          servoInit();
        else {
          for (uint8_t i = 0; i < 2; i++)
            _delay_ms(200);                     // sonst wird Impuls bereits vor erreichen der Mittelstellung abgeschaltet
          servoOff();
        }
        USART_Init_Baudrate();
  }
  Jump_Menu(pmenu);
}

/**************************/
/*               Optionen                 */
/*  Antennennachführung   */
/*                                                */
/**************************/
void Menu_Tracking_HYST(void)
{ uint32_t eep_val;

  Disp_Title(MSG_HYSTERESE);
  eep_val = Change_Value(track_hyst, TRACKING_HYST_MIN, TRACKING_HYST_MAX, 7, IDX_DISPL_FORMAT_INT, V_REPEAT); // pmenu gloabal
  if (eep_val != track_hyst) {
    track_hyst = eep_val;
        eeprom_write_byte(&ep_track_hyst, track_hyst);
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
  Jump_Menu(pmenu);
}

void Menu_Tracking_TXOSD(void)
{ uint32_t eep_val;

  Disp_Title(MSG_TRACK_TX_OSD_DATA);
  eep_val = Change_Value(track_tx, 0, 1, 3, IDX_DISPL_TRACK_TX, C_REPEAT); // pmenu global; Senden gibt es nur 0=off, 1=on
  if (eep_val != track_tx) {
    track_tx = eep_val;
        eeprom_write_byte(&ep_track_tx, track_tx);
        Double_Beep(DBEEPWR, DBEEPWRP);
  }
  Jump_Menu(pmenu);
}

void Menu_Baudrate(void)
{ uint32_t eep_val;

  Disp_Title(MSG_BAUDRATE);
  eep_val = Change_Value(baudrate, BAUDRATE_MIN, BAUDRATE_MAX, 3, IDX_DISPL_BAUDRATE, C_REPEAT); // pmenu global; Senden gibt es nur 0=off, 1=on
  if (eep_val != baudrate) {
    baudrate = eep_val;
        eeprom_write_byte(&ep_baudrate, baudrate);
        Double_Beep(DBEEPWR, DBEEPWRP);
        USART_Init(baud[baudrate]);
  }
  Jump_Menu(pmenu);
}

void Menu_Tracking_Option(void)
{ // im Menü ist dies der gleiche Gliederungspunkt aber mit geänderter Auswahl
  switch(tracking) {
    case TRACKING_RSSI:          Menu_Tracking_HYST();
                                                         break;
    case TRACKING_GPS:           Menu_Tracking_TXOSD();
                                                         break;
    case TRACKING_MKCOCKPIT: Menu_Baudrate();
  }
}

/**************************/
/*                                                */
/*      Anzeige GPS               */
/*                                                */
/**************************/
void Menu_GPS_Display(void)
{ uint8_t scr_sub_menu[4] = {MSG_RETURN, MSG_GPS_CALCULATE, MSG_GPS_CURRENT, MSG_GPS_HOME};

  Scroll_Menu(scr_sub_menu, 3, m_pkt); // pmenu global
  Jump_Menu(pmenu);
}

void Menu_GPS_Display_FLAG(void) // ist Flag in tracking.c Tracking_GPS(void)
{ uint8_t slen;
 
  slen = strlen(pmenu) - 1;
  gps_display = pmenu[slen] - '0';      // char to byte 1 bis 3 im String enthalten
  m_pkt = gps_display;
  gps_disp_clear = 1;                   // damit Text "...keine Daten empf..." nach Datenempfang gelöscht wird
  lcdPuts(Msg(MSG_GPS_NO_DATA));
  if (Short_Enter())                    // pmenu global
        pmenu[slen] = '\0';                     // Menüpunkt zurück
  gps_display = GPS_DISP_NONE;  // nach Tastaturabfrage keine Anzeige GPS, sondern normales Menü
  Jump_Menu(pmenu);
}