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 <avr/interrupt.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>

#include "config.h"
#include "ngvideo.h"
#include "keys.h"
#include "menue.h"
#include "servo.h"
#include "tracking.h"
#include "messages.c"
#include "dogm.h"
#include "tools.h"
#include "usart.h"
#include "ngvideo.h"

typedef uint8_t scr_menu_t[SCROLL_MAIN_MAX];
char pmenu[6] = {"0"};                  // Zuordnung Menü Programmgliederung zu hinterlegten Funktionen
uint8_t m_pkt;                                                  // um bei Rücksprung auf ursprünglichen Arrayeintrag(Menüpunkt), Scroll_Menu zeigen
uint8_t servo_nr;                                               // zwischen Servo 1 und 2 wird nur mit global servo_nr unterschieden
uint8_t chrxs;                                                  // zum Laden lcdSpecialChrLs oder lcdSpecialChrRs
uint8_t exit_while = 0;                 // unabhängige Task (z.B: Menu_MK_BatteryChangeNr() - Aufruf) kann Eingabe while-Schleife beenden, wenn 1

// Menügliederung im Flash belassen
const char cmdStr0[]                            PROGMEM = "0";
const char cmdStr01[]                           PROGMEM = "01";
const char cmdStr02[]                           PROGMEM = "02";
const char cmdStr03[]                           PROGMEM = "03";
const char cmdStr031[]                  PROGMEM = "031";
const char cmdStr032[]                  PROGMEM = "032";               
const char cmdStr033[]                  PROGMEM = "033";               
const char cmdStr04[]                           PROGMEM = "04";
const char cmdStr05[]                           PROGMEM = "05";
const char cmdStr051[]                  PROGMEM = "051";
const char cmdStr052[]                  PROGMEM = "052";        // zwischen Servo 1 und 2 wird danach
const char cmdStr0521[]                 PROGMEM = "0521";       // mit global servo_nr unterschieden
const char cmdStr0522[]                 PROGMEM = "0522";              
const char cmdStr0523[]                 PROGMEM = "0523";
const char cmdStr0524[]                 PROGMEM = "0524";
const char cmdStr053[]                  PROGMEM = "053";
const char cmdStr0531[]                 PROGMEM = "0531";
const char cmdStr0532[]                 PROGMEM = "0532";
const char cmdStr0533[]                 PROGMEM = "0533";
const char cmdStr0534[]                 PROGMEM = "0534";
const char cmdStr06[]                           PROGMEM = "06";
const char cmdStr061[]                  PROGMEM = "061";
const char cmdStr062[]                  PROGMEM = "062";
const char cmdStr0621[]                 PROGMEM = "0621";
const char cmdStr0622[]                 PROGMEM = "0622";
const char cmdStr0623[]                 PROGMEM = "0623";
const char cmdStr0624[]                 PROGMEM = "0624";
const char cmdStr0625[]                 PROGMEM = "0625";
const char cmdStr063[]                  PROGMEM = "063";
const char cmdStr064[]                  PROGMEM = "064";
const char cmdStr07[]                           PROGMEM = "07";
const char cmdStr071[]                  PROGMEM = "071";
const char cmdStr072[]                  PROGMEM = "072";
const char cmdStr08[]                           PROGMEM = "08";
const char cmdStr081[]                  PROGMEM = "081";
const char cmdStr082[]                  PROGMEM = "082";
const char cmdStr083[]                  PROGMEM = "083";
const char cmdStr0831[]                 PROGMEM = "0831";
const char cmdStr0832[]                 PROGMEM = "0832";
const char cmdStr0833[]                 PROGMEM = "0833";
const char cmdStr0834[]                 PROGMEM = "0834";
const char cmdStr0835[]                 PROGMEM = "0835";
const char cmdStr09[]                           PROGMEM = "09";
const char cmdStr0d[]                           PROGMEM = "0:";         // wird nur bei Tracking RSSI oder GPS eingeblendet - SCROLL_MAIN_MAX wird geändert
const char cmdStr0e[]                           PROGMEM = "0;";         // wird nur bei Tracking GPS eingeblendet                                        - SCROLL_MAIN_MAX wird geändert
const char cmdStr0e1[]                  PROGMEM = "0;1";        // nach '9' (0x39) folgt ':' (0x3a) ';' (0x3b)
const char cmdStr0e2[]                  PROGMEM = "0;2";       
const char cmdStr0e3[]                  PROGMEM = "0;3";
const char cmdStr0e4[]                  PROGMEM = "0;4";
const char cmdStr0e5[]                  PROGMEM = RXTimeStr;

command_table_t command_table[] PROGMEM =                       // Befehls-Tabelle
{
        {cmdStr0,               Menu_Main},
        {cmdStr01,              Menu_AV_Source},
        {cmdStr02,              Menu_RX_Channel},
        {cmdStr03,              Menu_RSSI_Calibr},
        {cmdStr031,             Menu_RSSI_min},
        {cmdStr032,             Menu_RSSI_min_all},            
        {cmdStr033,             Menu_RSSI_max},        
        {cmdStr04,              Menu_Language},
        {cmdStr05,              Menu_Servo_Calibr},
        {cmdStr051,             Menu_Servo_Steps},
        {cmdStr052,             Menu_Servo1},                                           // zwischen Servo 1 und 2 wird danach
        {cmdStr0521,    Menu_Servo1_rev},                               // mit global servo_nr unterschieden
        {cmdStr0522,    Menu_Servo1_left},             
        {cmdStr0523,    Menu_Servo1_right},
        {cmdStr0524,    Menu_Servo1_middle},
        {cmdStr053,             Menu_Servo2},
        {cmdStr0531,    Menu_Servo2_rev},
        {cmdStr0532,    Menu_Servo2_left},
        {cmdStr0533,    Menu_Servo2_right},
        {cmdStr0534,    Menu_Servo2_middle},
        {cmdStr06,              Menu_Servo_Test},
        {cmdStr061,             Menu_Test_PulseWidth},
        {cmdStr062,             Menu_Test_Continuous},
        {cmdStr0621,    Menu_Test_Start},
        {cmdStr0622,    Menu_Test_SingleStep},
        {cmdStr0623,    Menu_Test_Repeat},
        {cmdStr0624,    Menu_Test_Pause},
        {cmdStr0625,    Menu_Test_Pause_Step},
        {cmdStr063,             Menu_Test_ServoNr},
        {cmdStr064,             Menu_Test_Frame},
        {cmdStr07,              Menu_lcd},
        {cmdStr071,             Menu_lcd_Contrast},
        {cmdStr072,             Menu_lcd_Backgr_Light},
        {cmdStr08,              Menu_Battery},
        {cmdStr081,             Menu_Low_U_Setup},
        {cmdStr082,             Menu_U_Offset},
        {cmdStr083,             Menu_MK_Battery},
        {cmdStr0831,    Menu_MK_BatteryNr},
        {cmdStr0832,    Menu_MK_BatteryCapacity},
        {cmdStr0833,    Menu_MK_I_Offset},
        {cmdStr0834,    Menu_MK_I_Faktor},
        {cmdStr0835,    Menu_MK_W_Faktor},
        {cmdStr09,              Menu_Tracking_Ant},
        {cmdStr0d,              Menu_Tracking_Option},  // wird nur bei Tracking RSSI oder GPS eingeblendet - SCROLL_MAIN_MAX wird geändert
        {cmdStr0e,              Menu_GPS_Display},                      // wird nur bei Tracking GPS oder NMEA eingeblendet - SCROLL_MAIN_MAX wird geändert
        {cmdStr0e1,             Menu_GPS_Display_FLAG}, // nach '9' (0x39) folgt ':' (0x3a)
        {cmdStr0e2,             Menu_GPS_Display_FLAG},
        {cmdStr0e3,             Menu_GPS_Display_FLAG},
        {cmdStr0e4,             Menu_GPS_Display_FLAG},
        {cmdStr0e5,             Menu_GPS_Displ_RX_Time} // bei NMEA wird dieser Menüpunkt um 1 vorgezogen (anstelle GPS_MISC)
};


uint8_t Change_Value(uint16_t *val, uint16_t min_val, uint16_t max_val, uint8_t fl_pos, Displ_Fnct_t Displ_Fnct);


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

/************************************************************************************/
/*      sucht nach übergebenen String in der Kommandotabelle und springt zum daneben            */
/*      stehenden Menü-Programm                                                                                                                                                                                                                                 */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      char *pmenu             :zu suchender String in Kommandotabelle                                                                                                         */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Jump_Menu(char *pmenu)
{ uint8_t i;
        void (*func)(void);

        if (pmenu[0] != '\0'){
                for (i=0; i < sizeof(command_table) / sizeof(command_table_t); i++) {
                        // Ist das der gesuchte String?
                        if (!(strcmp_P(pmenu, (char*)pgm_read_word(&(command_table[i].menu_nr))))) {
                                func = (void(*)(void))pgm_read_word(&(command_table[i].fp));
                                func();
                                break;
                        }
                }
        }
}

/************************************************************************************/
/*                                                                                                                                                                                                                                                                                                                                      */
/*                                                                                      Abfrage Short- oder Long-Enter                                                                                                                  */
/*              verbleibt in Abfrage bis Enter betätigt; Rückgabe => Short-Enter True/False             */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
uint8_t Long_Enter(void)
{
        Tasks_invisible();      // Dadurch ist Doppelaufruf von MK-GPS möglich!!! Nur bei Menu_MK_BatteryChangeNr()
        // falls Akku leer ==> Menü verlassen und Anzeige __ACCU_LOW
        U_Messen_cmp(DISABLE_BTIMER);
        if (Get_Key_Long( 1<<SW_ENTER ) || bat_low) {
                pmenu[0] ='\0';         // direkt in das Hauptprogramm
                return 1;
        }
        else return 0;
}

uint8_t Short_Enter(void)
{ uint8_t ret;

        // bis Short- oder Long-Enter, auch Akku leer
        while( !Get_Key_Short( 1<<SW_ENTER ) && !Long_Enter() && !exit_while);
        lcdClear();
        if (pmenu[0] == '\0') Displ_Main_Disp(); else Beep(BEEPENTER); // bei ShortEnter Beep
        ret = (pmenu[0] != '\0') && !exit_while;
        exit_while = 0;
        return(ret); // ShortEnter bringt 1 zurück
}

/************************************************************************************/
/*                                                                                                                                                                                                                                                                                                                                      */
/*      Unterprogramm vom 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 i;
       
        if (scr_idx > 0) scr_idx--; else scr_idx = scr_menu[0];
        for (i = 0; i < LCD_LINES; i++) {
                lcdGotoXY(2, i);                                // LCD Beginn x-Position, 2 Zeichen rechts eingerückt
                lcdPuts(Msg(scr_menu[scr_idx + 1]));
                lcdClearEOL();                                  // ab Stringende bis zum Zeilenende löschen; LCD löschen flackert sonst zu sehr
                if (scr_idx < scr_menu[0]) scr_idx++; else scr_idx = 0;
        }
}

/************************************************************************************/
/*                                                                                                                                                                                                                                                                                                                                      */
/*      Unterprogramm vom Scroll_Menu(...) und Change_Value(...)                                                                                                */
/*      bei Rücksprung auf ursprünglichen Menüpunkt zeigen                                                                                                                      */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint8_t l               : Strinlänge von pmenue                                                                                                                                                                                 */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void return_m_pkt(uint8_t l)
{
        if (l > 1) {            // bei l=1 und Subtraktion 1 wird sowieso Displ_Main_Disp() ausgeführt und dort pmenu[0] = '\0' gesetzt
                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();
}

/************************************************************************************/
/*                                                                                                                                                                                                                                                                                                                                      */
/*      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 scr_idx)
{ uint8_t l;

        lcdClear();
        lcdGotoXY(0, 1);
        lcdPutc(MARKER_SELECT);         // '>>'
        Displ_Scroll_Menu(scr_menu, scr_idx);
        // bis Menueeingabe bestätigt oder zum vorherigen Menue
        while( !Get_Key_Short( 1<<SW_ENTER ) && !Long_Enter() && !exit_while)
        {
                // >> 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 = scr_menu[0];
                        Displ_Scroll_Menu(scr_menu, scr_idx);
                }      
                // >> Menueauswahl nach unten
                if( Get_Key_Press( 1<<SW_MINUS ) || Get_Key_Rpt( 1<<SW_MINUS )) {
                        if (scr_idx < scr_menu[0]) scr_idx++; else scr_idx = 0;
                        Displ_Scroll_Menu(scr_menu, scr_idx);
                }
        }

        lcdClear();
        if (exit_while)                                                                                 // wegen Aufruf Menu_MK_BatteryChangeNr() in Task
                m_pkt = scr_idx;                                                                        // nach Task Menu_MK_BatteryChangeNr() wieder zum ursprünlichen Anzeigepunkt
        else {
                l = strlen(pmenu);
                if ((scr_idx == 0) || (l == 0)) // long Enter wird durch l == 0 brücksichtigt
                        return_m_pkt(l);                                                                // um bei Rücksprung auf ursprünglichen Menüpunkt zu zeigen oder Displ_Main_Disp()
                else {
                        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] ='\0';
                        Beep(BEEPENTER);
                }
        }
        exit_while = 0;
}

/************************************************************************************/
/*                                                                                                                                                                                                                                                                                                                                      */
/*      Ändern der Werte mit Tasten +,- und Anzeige                                                                                                                                                     */
/*      z.B. für U-Offset, Batterie leer Eingabe ...                                                                                                                                            */
/*                                                                                                                                                                                                                                                                                                                                      */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t                        val                                     :zu ändernter Wert                                                                                                                                      */
/*      uint16_t min_val, max_val               :min, max Grenze Wert ändern darf                                                                               */
/*      uint8_t posX, posY                                      :Darstellung Wert xPos, YPos auf LCD                                                            */
/*      Displ_Fnct_t    Displ_Fnct              :Index um variable 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                                                  */
/*      uint16_t Change_Value_plmi(...)         :Rückgabe geänderter Wert                                                                                       */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
uint16_t Change_Value_plmi(uint16_t val, uint16_t min_val, uint16_t max_val, uint8_t posX, uint8_t posY, \
                                                                                                         Displ_Fnct_t Displ_Fnct, 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(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(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:                                                                                                                                                                                                                                                                                      */
/*      uint16_t *val                                           :zu ändernter Wert                                                                                                                                              */
/*      uint16_t min_val, max_val       :min, max Grenze Wert ändern darf                                                                                       */
/*      uint8_t fl_pos                                          :Bit 7 beschleunigte Repeat-Funktion aus/ein                                    */
/*                                                                                                               Bit 6 zyklische Werteänderung aus/ein                                                          */
/*                                                                                                               Bit 4-5  z.Z. ohne Funktion                                                                                                    */
/*                                                                                                               Bit 0-3 Wert xPos auf LCD                                                                                                              */
/*      Displ_Fnct_t Displ_Fnct         :Index um variable Display Funktion aufzurufen                          */
/*      uint8_t Change_Value(...)       :Rückgabe geändert ergibt TRUE                                                                                          */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
// Bei Bedarf könnte einfach innerhalp fl_pos auch noch pos_y (Bit 4-5) übergeben werden
uint8_t Change_Value(uint16_t *val, uint16_t min_val, uint16_t max_val, uint8_t fl_pos, Displ_Fnct_t Displ_Fnct)
{ uint16_t tmp_val;

        tmp_val = *val;
        lcdGotoXY(fl_pos & POSXMASK, ZLE_VAL);          // Position Wert
        Displ_Fnct(tmp_val);                                                                                    // initiale Wertdarstellung, je nach Menüpunkt
        if (pmenu[0] =='\0') strcpy(pmenu, "0");        // sonst wird eventuell nachfolgende while-Schleife nicht ausgeführt
        // bis Menueeingabe bestätigt oder zum vorherigen Menue
        while( !Get_Key_Short( 1<<SW_ENTER ) && !Long_Enter() && !exit_while)
                *val = Change_Value_plmi(*val, min_val, max_val, fl_pos & POSXMASK, ZLE_VAL, Displ_Fnct, fl_pos & (1<<CYCLE), fl_pos & (1<<V_REPEAT));
       
        lcdClear();
        if (exit_while) {
                exit_while = 0;
                *val = tmp_val;
        }
        else
                return_m_pkt(strlen(pmenu));            // um bei Rücksprung auf ursprünglichen Menüpunkt zeigen oder Displ_Main_Disp()
        return(tmp_val != *val);
}

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

/************************************************************************************/
/*      zeigt Menü-     * Überschrift * auf erste Zeile mittig auf Display an                                                           */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint8_t message         : index (MSG_) der darzustellenden Zeichenkette                                                         */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_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));
        delay_ms100x(30);
        lcdClear();
}

/************************************************************************************/
/*      zeigt auszuwählenden/-gewählten Kanal und Frequenz auf Display an                                                               */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t k                                              :Index anzuzeigender Wert = Kanal + 0x30 als Char,                              */
/*                                                                                               uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                   */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Channels(uint16_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:                                                                                                                                                                                                                                                                                      */
/*      uint16_t q                                              :Index anzuzeigender Wert,                                                                                                                              */
/*                                                                                               unint16_t wegen Vereinheitlichung f. Funktionsaufrauf          */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_AV_Source(uint16_t q)
{ uint8_t av_src_table[] = {MSG_AV1, MSG_AV2, MSG_DIVERSITY};

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

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

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

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

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

/************************************************************************************/
/*      zeigt einen max. 3-stelligen Integerwert auf Display an                                                                                                 */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val                            :anzuzeigender Wert,                                                                                                                                                            */
/*                                                                                       uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                           */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Format_Int(uint16_t val)
{
        lcdPuts(my_itoa(val, 3, 0, 0));
}

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

/************************************************************************************/
/*      zeigt die Zeit zur Abschaltung der LCD-Hintergrundbeleuchtung an                                                                */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val                            :anzuzeigender Wert,                                                                                                                                                            */
/*                                                                                       uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                           */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Backgr_Light(uint16_t val)
{ char str[5];

        switch(val) {
                case BACKGR_LIGHT_MIN : lcdPuts(Msg(MSG_LIGHT_OFF));
                                                                                                                break;
                case BACKGR_LIGHT_MAX : lcdPuts(Msg(MSG_LIGHT_ON));
                                                                                                                break;
                default :                                                       itoa (val * 10, str, 10);
                                                                                                                lcdPutc(' ');
                                                                                                                lcdPuts(str);
                                                                                                                lcdPuts(Msg(MSG_SEC));
        }
        lcdClearEOL();
}

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

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

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

/************************************************************************************/
/*      zeigt Servo-Anschlagposition links auf Display an                                                                                                                       */
/*      mit sofortiger Wirkung auf Servo                                                                                                                                                                                                */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val                            :anzuzeigender Wert,                                                                                                                                                            */
/*                                                                                       uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                           */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Servo_Min(uint16_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:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val                            :anzuzeigender Wert,                                                                                                                                                            */
/*                                                                                       uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                           */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Servo_Max(uint16_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:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val                            :anzuzeigender Wert,                                                                                                                                                            */
/*                                                                                       uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                           */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Servo_Mid(uint16_t val)
{ int16_t mid_val;
       
        mid_val = val - ServoSteps()/2;
        lcdPuts(my_itoa(mid_val, 4, 0, 0));
        servoSet_mid(servo_nr, val);                                                                    // Wert setzen damit nachfolgend die
        servoSetPosition(servo_nr, ServoSteps()/2);     // Änderung direkt am Servo sichtbar ist
}

/************************************************************************************/
/*      zeigt zu testende Servonummer zur Auswahl auf Display an                                                                                                */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val                            :0 = Servo 1 oder 1 = Servo 2,                                                                                                                  */
/*                                                                                       uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                           */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_ServoNr(uint16_t val)
{
        if (val == 0) lcdPuts(Msg(MSG_SERVO1)); else lcdPuts(Msg(MSG_SERVO2));
}


/************************************************************************************/
/*      zeigt Servoausschlag in ms, in % und als Bargraph auf Display an                                                                */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      int16_t PosProzent      : aktuell eingestellte Position vom 0-Punkt (Mitte) aus                 */
/*      int16_t range                           : maximaler absoluter Ausschlag vom 0-Punkt aus                                                 */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
// leerer Rahmen für Bar
char* empty_Bar(void)
{ static char tmp_empty[LCD_COLS];
        uint8_t i;
       
        tmp_empty[0] = '\0';                    // '['
        for (i = 1; i < 15; i++)
                tmp_empty[i] = '\x07';
        tmp_empty[i] = '\x06';          // ']'
        return(tmp_empty);
}

void draw_bar(int16_t PosProzent, int16_t range, uint8_t zle)
{ int8_t i, sp_quad, sp_ch;
        int8_t lz = 8;
        char* bar;
               
        bar = empty_Bar();                                                                                              // leerer Rahmen für Bar
        sp_quad = abs(PosProzent) * 7 / range;          // Anzahl der vollen Kästchen

        sp_ch = (abs(PosProzent) -(range * sp_quad / 7)) * 35 / range; // Unterteilung Kästchen in 6 senkrechte Striche
        if (sp_ch > 4) sp_ch = 4; // bei 28 (7*4) wäre keine Korrektur erforderlich aber so kontinuierlicher
        if (PosProzent < 0){
                lz -=   sp_quad;                                                                                                        // Position für volles Kästchen bei Linksausschlag
                if (sp_ch > 0) bar[lz-1] = sp_ch;                       // vor erstes volles Kästchen Kästchenunterteilung schreiben
        }                                                                                                                                                                       // Unterteilung Kästchen der 4 senkrechte Striche nach Bar (0 und 5 entfallen)
        else
                if (sp_ch > 0) bar[lz+sp_quad] = sp_ch;// nach lezten vollen Kästchen Kästchenunterteilung schreiben

        for (i = 0; i < sp_quad; i++)
                bar[i+lz] = '\x05';                                                                                     // volle Kästchen schreiben
        lcdGotoXY(0,zle);
        for (uint8_t i = 0; i < LCD_COLS; i++) lcdPutc(bar[i]);// kpl. Bar zum Display
}

uint16_t calc_range(int16_t PosProzent, int16_t min, int16_t max, int16_t mid)
{ uint16_t range;

        if (PosProzent < 0) {
                range = mid - min;
                if (chrxs == CHRRS) {           // falls Richtung geändert, anderen Zeichensatz laden
                        chrxs = CHRLS;
                        lcdWriteCGRAM_Array(lcdSpecialChrLs, 5);// LCD-Char mit Rahmensymbole vom Graph
                }
        }
        else {
                range = max - mid;
                if (chrxs == CHRLS) {           // falls Richtung geändert, anderen Zeichensatz laden
                        lcdWriteCGRAM_Array(lcdSpecialChrRs, 5);// LCD-Char mit Rahmensymbole vom Graph
                        chrxs = CHRRS;
                }
        }
        return(range);
}

void Displ_PulseWidth(uint16_t val)
{ int16_t PosProzent, range;
        uint16_t Pos_us;
        char me[3] = {"ms"};

        servoSetPositionRaw(servo_nr, val);
       
        PosProzent = val - steps_pw[sIdxSteps].mid;
        range = calc_range(PosProzent, steps_pw[sIdxSteps].min, steps_pw[sIdxSteps].max, steps_pw[sIdxSteps].mid);
        draw_bar(PosProzent, range, 2); // auf 3. Display-Zeile
        PosProzent = (int32_t)1000 * PosProzent / range;
        lcdGotoXY(1, 1);
        Pos_us = pw_us(val);    // Zeit in µs bei x Servoschritte
        if (Pos_us < 1000) {
                me[0] = 'u';                            // soll 'µ' => programmierbarer Zeichensatz zu klein
                lcdPuts("  ");
                Displ_Format_Int(Pos_us);
        }
        else {
                lcdPuts(my_itoa(Pos_us, 5, 3, 3));
        }
        lcdPuts(me);
        lcdGotoXY(8, 1);
        lcdPuts(my_itoa(PosProzent, 6, 1, 1));
        lcdPutc('%');
}

/************************************************************************************/
/*      zeigt Pausenlänge der Links-, Mittel- und Rechtsposition auf Display an                                 */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val            : Zeit in 1ms * 100                                                                                                                                                                                     */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Pause(uint16_t val)
{
        if (val > 9) {
                lcdPuts(my_itoa(val, 3, 1, 1));
                lcdPuts("s ");
        }
        else {
                Displ_Format_Int(val * 100);
                lcdPuts("ms");
        }
}

/************************************************************************************/
/*      zeigt aus oder Integerwert auf Display an                                                                                                                                                               */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val            : val = 0 ==> aus, sont Integerwert                                                                                                                     */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Off_Format_Int(uint16_t val)
{
        if (val == 0)
                lcdPutStrMid(Msg(MSG_OFF), ZLE_VAL);
        else {
                lcdGotoXY(5,ZLE_VAL);
                Displ_Format_Int(val);
                lcdPutc(' ');
        }
}

/************************************************************************************/
/*      zeigt aus oder Pausenzeit zwischen 2 Servoschritte auf Display an                                                               */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val            : val = 0 ==> aus, sont Integerwert                                                                                                                     */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Pause_Step(uint16_t val)
{
        Displ_Off_Format_Int(val);
        if (val > 0) {
                lcdGotoXY(8,ZLE_VAL);
                lcdPuts("ms");
        }
}
/************************************************************************************/
/*      zeigt Baudrate für COM bei MKCockpit zur Auswahl auf Display an                                                                 */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t q                                              :Index anzuzeigender Wert,                                                                                                                              */
/*                                                                                               uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                   */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Baudrate(uint16_t q)
{ char str[7];

        ltoa(getBaud(q), str, 10);
        lcdPutStrMid(str, ZLE_VAL);
}

/************************************************************************************/
/*      zeigt aktive Empfängerzeiten auf Display an                                                                                                                                                     */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_RX_Time(void)
{
        lcdGotoXY(6, 1);
        Displ_TimeHMS(rxcount0);
        lcdGotoXY(6, 2);
        Displ_TimeHMS(rxcount1);
}

/************************************************************************************/
/*      zeigt eingestellte Akku-Kapazität des MK auf Display an                                                                                                 */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val                            :Akku-Kapazität in 50mAh Schritte                                                                                                               */
/*                                                                                       uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                           */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_MK_Capacity(uint16_t val)
{
        lcdPuts(my_itoa(val * 50, 4, 0, 0));
        lcdPuts("mAh");
}

/************************************************************************************/
/*      zeigt Offset (Korrektur Ruhestrom) für Strom des MK auf Display an                                                      */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val                            :Korrekturfaktor                                                                                                                                                                                */
/*                                                                                       uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                           */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_I_Offset(uint16_t val)
{
        lcdPuts(my_itoa((int8_t)val - MK_I_OFFSET_5,4,1,1));
        lcdPutc('A');
}


/************************************************************************************/
/*      zeigt Korrekturfaktor für Strom und Arbeit des MK auf Display an                                                                */
/*      Parameter:                                                                                                                                                                                                                                                                                      */
/*      uint16_t val                            :Korrekturfaktor                                                                                                                                                                                */
/*                                                                                       uint16_t wegen Vereinheitlichung f. Funktionsaufrauf                           */
/*                                                                                                                                                                                                                                                                                                                                      */
/************************************************************************************/
void Displ_Faktor_2Nk(uint16_t val)
{
        lcdPuts(my_itoa(val,4,2,2));
}

/************************************************************************************/
/*      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 SetAndDispl_AV_Mark(void)
{ char marker;

        marker = av_source < DIVERSITY? MARKER_AV : MARKER_RSSI;                // wird nur bei gesetzten Diversity überschrieben
        Displ_AV_Mark(sw_avx, marker);
}

void Displ_Main_Disp(void)
{
        pmenu[0] ='\0';                                         // bei Direktansprung z.B. von Menu_RSSI_min() erforderlich
        lcdClear();
        if (!bat_low) {
                lcdClear();
                Displ_Channels(channel);
                lcdGotoXY(LCD_COLS - 1, 0);
                lcdPuts("V\n1\n2");
                SetAndDispl_AV_Mark();
                Displ_VBat();                                   // muss zuletzt stehen
        }
        else {
                lcdPutStrMid(Msg(MSG_ACCU_LOW), 0);
        }
}



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

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

        switch(tracking) {
                case TRACKING_RSSI:                      scr_main_menu[11] = MSG_TRACK_SERVO_HYTERESE;
                                                                                                                 scr_main_menu[0]++;            // SCROLL_MAIN_MAX erhöhen
                                                                                                                 break;
                case TRACKING_GPS:                       scr_main_menu[11] = MSG_TRACK_TX_OSD_DATA;
                                                                                                                 scr_main_menu[0] += 2; // SCROLL_MAIN_MAX erhöhen, zusätzliche Anzeige zu GPS MSG_GPS_DISPLAY
                                                                                                                 break;
                case TRACKING_NMEA:                      scr_main_menu[0]++;            // SCROLL_MAIN_MAX erhöhen, zusätzliche Anzeige zu GPS
                case TRACKING_MKCOCKPIT: scr_main_menu[0]++;            // SCROLL_MAIN_MAX erhöhen
                                                                                                                 scr_main_menu[11] = MSG_COM;
                                                                                                                 break;
        }
       
        strcpy(pmenu, "0");
        Scroll_Menu(scr_main_menu, m_pkt);      // pmenu global
        Jump_Menu(pmenu); //gewähltes Untermenü anspringen oder nur Return
}

/**************************/
/*                                                                                              */
/*                              AV-Quelle                               */
/*                                                                                              */
/**************************/
void Menu_AV_Source(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_AV_SOURCE);
        tmp_val = av_source;
        if (Change_Value(&tmp_val, AV_SOURCE_MIN, AV_SOURCE_MAX, 3, Displ_AV_Source)) { // pmenu global
                cli();
                av_source = tmp_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 bei long Enter im Hauptdisplay nicht aktuallisiert
                        SetAndDispl_AV_Mark();
                sei();
        }
        Jump_Menu(pmenu);
}

/**************************/
/*                                                                                              */
/*                              Kanal                                           */
/*                                                                                              */
/**************************/
void Menu_RX_Channel(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_RX_CHANNEL);
        tmp_val = channel;
        if (Change_Value(&tmp_val, CHANNEL_MIN, CHANNEL_MAX, 3, Displ_Channels) || (tmp_val != ch_stored)) {    // pmenu global
                channel = tmp_val;
                ch_stored = tmp_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[SCROLL_MAX_5]    = {SCROLL_MAX_5-2, MSG_RETURN, MSG_RSSI_MIN, MSG_RSSI_MIN_ALL, MSG_RSSI_MAX};

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

void AdviceTX(uint8_t msg)
{ char str[20];

        strcpy(str, Msg(MSG_TX));
        strcat(str, Msg(msg));
        lcdPutStrMid(str, 1);
        lcdPutStrMid(Msg(MSG_CONTINUE), 2);
}

void Menu_RSSI_min(void)
{
        Displ_Title(MSG_RSSI_MIN);
        AdviceTX(MSG_TX_OFF);
        if (Short_Enter()) {                                                    // pmenu global
                RSSI_Min_Calibrate(0, bar_udbm);
                Displ_Main_Disp();                                                      // da erst jetzt die Variable für main_display geändert ist!
        }
        else
                Jump_Menu(pmenu);
}

void Displ_RSSImin_allError(char *str_ch)
{ char str[LCD_COLS + 1];
       
        lcdClear();
        strcpy(str, Msg(MSG_CALIB));
        strcat(str, "-");
        strcat(str, Msg(MSG_ERROR));
        lcdPutStrMid(str,0);
        lcdPutStrMid(Msg(MSG_RX_CHANNEL),1);
        lcdPutStrMid(str_ch, 2);
        delay_ms100x(30);
}

void Menu_RSSI_min_all(void)
{ char not_cal[15];
        uint8_t f = 0;

        Displ_Title(MSG_RSSI_MIN_ALL);
        AdviceTX(MSG_TX_OFF);
        if (Short_Enter()) {                                            // pmenu global
                for ( uint8_t i = 1; i <= CHANNEL_MAX; i++) {
                        Set_Channel(i);
                        if (!RSSI_Min_Calibrate(i, bar_udbm)) {
                                not_cal[f++] = i + 0x30;
                                not_cal[f++] = ',';
                        }
                }
                Set_Channel(channel);
                Double_Beep(DBEEPWR, DBEEPWRP);
                if (f > 0) {                                                            // Konnten einige Kanäle nicht auf RSSI-Min kalibiert werden?
                        not_cal[--f] = '\0';                    // letzes Komma durch Stringende ersetzen
                        Displ_RSSImin_allError(not_cal);
                }
                Displ_Main_Disp();
        }
        else
                Jump_Menu(pmenu);
}

void Menu_RSSI_max(void)
{
        Displ_Title(MSG_RSSI_MAX);
        AdviceTX(MSG_TX_ON);
        if (Short_Enter()) {                                    // pmenu global
                RSSI_Max_Calibrate(bar_udbm);
                Displ_Main_Disp();
        }
        else
                Jump_Menu(pmenu);
}

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

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

void Menu_Language(void)
{ uint16_t tmp_val;

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

/**************************/
/*                                                                                              */
/*      Servo-Einstellungen             */
/*                                                                                              */
/**************************/
void Menu_Servo_Calibr(void)
{ uint8_t scr_sub_menu[SCROLL_MAX_5] = {SCROLL_MAX_5 - 2, MSG_RETURN, MSG_SERVO_STEPS, MSG_SERVO1, MSG_SERVO2};

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

void NoTracking_ServosOff(void)
{
        if (tracking == TRACKING_MIN) {
                delay_ms100x(4);                                // sonst werden Impulse bereits vor erreichen der Servo-default-Stellung abgeschaltet
                servoOff();                                                     // Servos sind nur zum Tracking oder bei Kalibrierung eingeschaltet
        }
}

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    = (servo[i].mid + 1) * 4 - 1;
                }
                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)
{ uint16_t tmp_val;
         
        Displ_Title(MSG_SERVO_STEPS);
        lcdGotoXY(8, ZLE_VAL);
        tmp_val = sIdxSteps;
        if (Change_Value(&tmp_val, STEPS_255, STEPS_1023, 5, Displ_Servo_Steps)) { // pmenu global
                cli();
                sIdxSteps = tmp_val;
                eeprom_write_byte(&ep_sIdxSteps, sIdxSteps);
                Servo_NewValues(sIdxSteps);                             // hier ist der neue Index anzugeben!
                servoInit(SERVO_PERIODE);
                sei();
                NoTracking_ServosOff();
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

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

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

uint8_t Servo_tmp_on(uint8_t servo_period)
{ uint8_t tmp_tracking = tracking;

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

void Servo_tmp_Original(uint8_t track)
{
        servoSetDefaultPos();
        tracking = track;                                                                               // ursprünglicher Wert Tracking aus, RSSI oder GPS
        NoTracking_ServosOff();                                                 // Servos sind nur zum Tracking oder bei Kalibrierung eingeschaltet
        Jump_Menu(pmenu);
}

void Menu_Servo_rev(void)
{ uint16_t tmp_val;
        uint8_t tmp_tracking;

        tmp_tracking = Servo_tmp_on(SERVO_PERIODE);
        tmp_val = servo[servo_nr].rev;
        if (Change_Value(&tmp_val , 0, 1, 6, Displ_Off_On)) { // pmenu global; reverse gibt es nur 0=off, 1=on
                servo[servo_nr].rev = tmp_val ;
                servoSet_rev(servo_nr, tmp_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)
{
        Displ_Title(MSG_SERVO1_REVERSE);
        Menu_Servo_rev();
}

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

void Menu_Servo_left(void)
{ uint16_t tmp_val;
        uint8_t tmp_tracking;

        tmp_tracking = Servo_tmp_on(SERVO_PERIODE);
        servoSetPosition(servo_nr, ServoSteps());                               // Linkssanschlag um Kalibrierung am Servo zu sehen
        tmp_val = servo[servo_nr].max;
        if (Change_Value(&tmp_val, servo_limit[sIdxSteps][LEFT].min, servo_limit[sIdxSteps][LEFT].max, 6|(1<<V_REPEAT), Displ_Servo_Max)) { // pmenu global
                servo[servo_nr].max = tmp_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)
{
        Displ_Title(MSG_CALIB1_LEFT);
        Menu_Servo_left();
}

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

void Menu_Servo_right(void)
{ uint16_t tmp_val;
        uint8_t tmp_tracking;

        tmp_tracking = Servo_tmp_on(SERVO_PERIODE);
        servoSetPosition(servo_nr, 0);                                                                          // Rechtsanschlag um Kalibrierung am Servo zu sehen
        tmp_val = servo[servo_nr].min;
        if (Change_Value(&tmp_val, servo_limit[sIdxSteps][RIGHT].min, servo_limit[sIdxSteps][RIGHT].max, 6|(1<<V_REPEAT), Displ_Servo_Min)) { // pmenu global
                servo[servo_nr].min = tmp_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)
{
        Displ_Title(MSG_CALIB1_RIGHT);
        Menu_Servo_right();
}

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

void Menu_Servo_middle(void)
{ uint16_t tmp_val;
        uint8_t tmp_tracking;

        tmp_tracking = Servo_tmp_on(SERVO_PERIODE);
        servoSetPosition(servo_nr, ServoSteps()/2);                     // Mittelposition um Kalibrierung am Servo zu sehen
        tmp_val = servo[servo_nr].mid;
        if (Change_Value(&tmp_val, servo_limit[sIdxSteps][MIDDLE].min, servo_limit[sIdxSteps][MIDDLE].max, 5|(1<<V_REPEAT), Displ_Servo_Mid)) { // pmenu global
                servo[servo_nr].mid = tmp_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)
{
        Displ_Title(MSG_CALIB1_MIDDLE);
        Menu_Servo_middle();
}

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

/**************************/
/*                                                                                              */
/*                      Servos-Tests                    */
/*                                                                                              */
/**************************/
void Menu_Servo_Test(void)
{ uint8_t scr_sub_menu[SCROLL_MAX_6]    = {SCROLL_MAX_6 - 2, MSG_RETURN, MSG_PULSE_WIDTH, MSG_CONTINOUS, MSG_SERVO, MSG_FRAME};

        Scroll_Menu(scr_sub_menu, m_pkt); // pmenu global
        servo_nr = eeprom_read_byte(&ep_servo_nr);
        Jump_Menu(pmenu);
}

void Menu_Test_Frame(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_FRAME);
        lcdGotoXY(8, ZLE_VAL);
        lcdPuts("ms");
        tmp_val = servo_frame;
        if (Change_Value(&tmp_val, SERVO_PERIODE_MIN, SERVO_PERIODE_MAX, 5|(1<<V_REPEAT), Displ_Format_Int)) { // pmenu global
                servo_frame = tmp_val;
                eeprom_write_byte(&ep_servo_frame, servo_frame);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

void Menu_Test_ServoNr(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_SERVO);
        tmp_val = servo_nr;
        if (Change_Value(&tmp_val, 0, 1, 4, Displ_ServoNr)) { // pmenu global; es gibt nur 0=Servo1, 1=Servo2
                servo_nr = tmp_val;
                eeprom_write_byte(&ep_servo_nr, servo_nr);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

// Dieser Test im raw-Modus ohne Anschlagkalibrierung (normiert) z.B.: für Modelleinstellungen ohne Empfänger
void Menu_Test_PulseWidth(void)
{ uint8_t tmp_tracking;
        uint16_t tmp_val;
       
        tmp_tracking = Servo_tmp_on(servo_frame);
        lcdWriteCGRAM_Array(lcdSpecialChrLs, 8);        // LCD-Char mit Rahmensymbole vom Graph
        chrxs = CHRLS;                                                                                                          // verhindert wiederholtes Lesen bereits geladener LCD-Char
        Displ_Title(MSG_PULSE_WIDTH);
        tmp_val = steps_pw[sIdxSteps].mid;
        Change_Value(&tmp_val, steps_pw[sIdxSteps].min, steps_pw[sIdxSteps].max, 4|(1<<V_REPEAT), Displ_PulseWidth); // pmenu global
        lcdWriteCGRAM_Array(lcdSpecialChr, 7);          // LCD-Char für Bargraph zurückschreiben
        cli();
        servoInit(SERVO_PERIODE);
        sei();
        Servo_tmp_Original(tmp_tracking);
}

void Menu_Test_Continuous(void)
{ uint8_t scr_sub_menu[SCROLL_MAX_7]    = {SCROLL_MAX_7 - 2, MSG_RETURN, MSG_START, MSG_SINGLE_STEP, MSG_REPEAT, MSG_PAUSE, MSG_PAUSE_STEP};

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

void Menu_Test_SingleStep(void)
{uint16_t tmp_val;

        Displ_Title(MSG_SINGLE_STEP);
        tmp_val = single_step;
        if (Change_Value(&tmp_val, SINGLE_STEP_MIN, SINGLE_STEP_MAX, 5|(1<<V_REPEAT), Displ_Off_Format_Int)) { // pmenu global
                single_step = tmp_val;
                eeprom_write_byte(&ep_single_step, single_step);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

void Menu_Test_Repeat(void)
{uint16_t tmp_val;

        Displ_Title(MSG_REPEAT);
        tmp_val = repeat;
        if (Change_Value(&tmp_val, REPEAT_MIN, REPEAT_MAX, 5|(1<<V_REPEAT), Displ_Format_Int)) { // pmenu global
                repeat = tmp_val;
                eeprom_write_byte(&ep_repeat, repeat);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

void Menu_Test_Pause(void)
{uint16_t tmp_val;

        Displ_Title(MSG_PAUSE);
        tmp_val = pause;
        if (Change_Value(&tmp_val, PAUSE_MIN, PAUSE_MAX, 5|(1<<V_REPEAT), Displ_Pause)) { // pmenu global
                pause = tmp_val;
                eeprom_write_byte(&ep_pause, pause);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

void Menu_Test_Pause_Step(void)
{uint16_t tmp_val;

        Displ_Title(MSG_PAUSE_STEP);
        tmp_val = pause_step;
        if (Change_Value(&tmp_val, PAUSE_STEP_MIN, PAUSE_STEP_MAX, 5|(1<<V_REPEAT), Displ_Pause_Step)) { // pmenu global
                pause_step = tmp_val;
                eeprom_write_byte(&ep_pause_step, pause_step);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

int8_t calc_dir(uint8_t idx, int16_t *Position)
{ uint8_t nextIdx;
        int8_t nextDir = 1;

        nextIdx = idx;
        if ((idx + 1) < POSIDX_MAX)
                nextIdx++;
        else
                nextIdx = 0;
        if (Position[PosIdx[idx]] > Position[PosIdx[nextIdx]]) nextDir = -1;
        return(nextDir);
}

void Displ_LoopCounter(uint8_t val)
{
        lcdGotoXY(2,2);
        lcdPuts(Msg(MSG_COUNTER));
        lcdPuts(my_itoa(val, 4, 0, 0));
}

// Test über Scalierung der Servos mit Anschlagkalibrierung
void Menu_Test_Start(void)
{ uint8_t tmp_tracking, idx, rep;
        int8_t dir;
        int16_t sPos;
        int16_t Position[3];   
        int16_t range;
         
        tmp_tracking = Servo_tmp_on(servo_frame);
        lcdWriteCGRAM_Array(lcdSpecialChrLs, 8);                // LCD-Char mit Rahmensymbole vom Graph
        chrxs = CHRLS;                                                                                                                  // Flag, welche Kästchensymbole geladen
        Displ_Title(MSG_CONTINOUS);
        Displ_LoopCounter(repeat);
        Position[0] = 0;                                                                                                                // skalierte Servoposition aber unterschiedliche Schrittanzahl möglich
        Position[1] = ServoSteps()/2;
        Position[2] = ServoSteps();
        // init Einzelschritt
        idx = 0;
        dir = calc_dir(idx, Position);
        sPos = Position[PosIdx[idx]];
        idx++;
        rep = repeat;
       
        // Test bis Ende der Wiederholungen oder irgendein Enter
        while( !Get_Key_Short( 1<<SW_ENTER ) && !Long_Enter() && (rep > 0)) {  
                range = calc_range(sPos - Position[1], Position[0], Position[2], Position[1]);
                draw_bar(sPos - Position[1], range, 1); // eingerahmter Balkengraph auf 2. Display-Zeile
                servoSetPosition(servo_nr, sPos);

                if ( sPos != Position[PosIdx[idx]]) {           // Links-, Mittel- oder Rechtsposotion erreicht?
                        sPos += (single_step * dir);                                            // variable Schrittweite subtrahieren oder addieren
                        if (((dir < 0) && (sPos < Position[PosIdx[idx]])) || ((dir > 0) && (sPos > Position[PosIdx[idx]])) || !(single_step))
                                sPos = Position[PosIdx[idx]];                           // Überlauf bei variabler Schrittweite berücksichtigen oder Einzelschritt
                        _delay_ms(servo_frame + 1 + pause_step);// Bei Schrittweite um 1 würden welche übersprungen, zusätzlich pro Servoschritt verzögert
                }
                else {
                        dir = calc_dir(idx, Position);                                  // Richtungsänderung
                        if (idx < (POSIDX_MAX - 1)) {
                                if (idx == 0) {
                                        rep--;                                                                                                                  // bei jeden vollen Durchlauf Wiederholzähler verringern
                                        Displ_LoopCounter(rep);
                                }
                                idx++;                                                                                                                          // Index für nächsten Positionswert ==> Array PosIdx[] bestimmt Anschlagreihenfolge
                        }
                        else
                                idx = 0;
                        delay_ms100x(pause);                                                                            // variable Pause bei Links-, Mittel- und Rechtsposotion Mindestzeit 400ms (Servolauf)
                }
        }

        lcdClear();
        if (pmenu[0] == '\0')
                Displ_Main_Disp();
        else
                return_m_pkt(strlen(pmenu));                                                    // um bei Rücksprung auf ursprünglichen Menüpunkt zeigen oder Displ_Main_Disp()
        lcdWriteCGRAM_Array(lcdSpecialChr, 7);                  // LCD-Char für Bargraph zurückschreiben
        cli();
        servoInit(SERVO_PERIODE);
        sei();
        Servo_tmp_Original(tmp_tracking);
}


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

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

void Menu_lcd_Contrast(void)
{ uint16_t tmp_val;

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

void Menu_lcd_Backgr_Light(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_BACKGR_LIGHT);
        lcdGotoXY(0, ZLE_VAL);
        lcdPuts(Msg(MSG_LIGHT));
        tmp_val = light_time;
        if (Change_Value(&tmp_val, BACKGR_LIGHT_MIN, BACKGR_LIGHT_MAX, 6|(1<<V_REPEAT), Displ_Backgr_Light)) { // pmenu global
                light_time = tmp_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[SCROLL_MAX_5] = {SCROLL_MAX_5 - 2, MSG_RETURN, MSG_U_SETUP, MSG_U_OFFSET, MSG_MK_BATTERY};

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

/*****************/
/* NG-Video Akku */
/*****************/
void Menu_Low_U_Setup(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_U_MIN);
        tmp_val = u_min;
        if (Change_Value(&tmp_val, U_MIN_MIN, U_MIN_MAX, 4|(1<<V_REPEAT), Displ_U_2Nk)) { // pmenu global
                u_min = tmp_val;
                eeprom_write_word(&ep_u_min, u_min);
                hyst_u_min = u_min;
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

void Menu_U_Offset(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_U_OFFSET);
        tmp_val = u_offset;
        if (Change_Value(&tmp_val, U_OFFSET_MIN, U_OFFSET_MAX, 4|(1<<V_REPEAT), Displ_U_2Nk)) { // pmenu global
                u_offset = tmp_val;
                eeprom_write_byte(&ep_u_offset, u_offset);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

/******************/
/*       MK-Akku(s)             */
/******************/
void Menu_MK_Battery(void)
{ uint8_t scr_sub_menu[SCROLL_MAX_7] = {SCROLL_MAX_7 - 2, MSG_RETURN, MSG_MK_BAT_NR, MSG_MK_BAT_CAPACITY, MSG_MK_I_OFFSET, MSG_MK_I_FAKTOR, MSG_MK_W_FAKTOR};

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

// für Nutzung verschiedener Akku's unterschiedlicher Kapazität
// könnte auch für Statistik Ladezyklen erweitert werden aber sinnlos bei Verwendung gleicher Akku's in anderen Modellen
void Menu_MK_BatteryChangeNr(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_MK_BAT_NR);
        tmp_val = mk_akku_nr+1;
        if (Change_Value(&tmp_val, AKKU_NR_MIN+1, AKKU_NR_MAX+1, 5|(1<<V_REPEAT), Displ_Format_Int)) { // pmenu global
                mk_akku_nr = --tmp_val;
                eeprom_write_byte(&ep_mk_akku_nr, mk_akku_nr);
                eeprom_read_block(&mk_lipo,&ep_mk_lipo[mk_akku_nr],sizeof(mk_lipo_t));
                mk_dUsedCapacity = mk_lipo.UsedCapacity;
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
}

void Menu_MK_BatteryNr(void)
{
        Menu_MK_BatteryChangeNr();
        Jump_Menu(pmenu);
}

void Menu_MK_BatteryCapacity(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_MK_BAT_CAPACITY);
        tmp_val = mk_lipo.Capacity/50;
        if (Change_Value(&tmp_val, AKKU_CAPACITY_MIN/50, AKKU_CAPACITY_MAX/50, 5|(1<<V_REPEAT), Displ_MK_Capacity)) { // pmenu global
                mk_lipo.Capacity = tmp_val * 50;
                eeprom_write_block(&mk_lipo,&ep_mk_lipo[mk_akku_nr],sizeof(mk_lipo_t));
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

void Menu_MK_I_Offset(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_MK_I_OFFSET);
        tmp_val = mk_i_offset;
        if (Change_Value(&tmp_val, MK_I_OFFSET_MIN, MK_I_OFFSET_MAX, 5|(1<<V_REPEAT), Displ_I_Offset)) { // pmenu global
                mk_i_offset = tmp_val;
                eeprom_write_byte(&ep_mk_i_offset, mk_i_offset);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

void Menu_MK_I_Faktor(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_MK_I_FAKTOR);
        tmp_val = mk_i_faktor;
        if (Change_Value(&tmp_val, MK_I_FAKTOR_MIN, MK_I_FAKTOR_MAX, 6|(1<<V_REPEAT), Displ_Faktor_2Nk)) { // pmenu global
                mk_i_faktor = tmp_val;
                eeprom_write_byte(&ep_mk_i_faktor, mk_i_faktor);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

void Menu_MK_W_Faktor(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_MK_W_FAKTOR);
        tmp_val = mk_w_faktor;
        if (Change_Value(&tmp_val, MK_W_FAKTOR_MIN, MK_W_FAKTOR_MAX, 6|(1<<V_REPEAT), Displ_Faktor_2Nk)) { // pmenu global
                mk_w_faktor = tmp_val;
                eeprom_write_byte(&ep_mk_w_faktor, mk_w_faktor);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}


/**************************/
/*                                                                                              */
/*      Antennennachführung             */
/*                                                                                              */
/**************************/
void Menu_Tracking_Ant(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_TRACKING);
        tmp_val = tracking;
        if (Change_Value(&tmp_val, TRACKING_MIN, TRACKING_MAX, 3, Displ_sel_Tracking)) { // pmenu global
                cli();
                tracking = tmp_val;
                sei();
                eeprom_write_byte(&ep_tracking, tracking);
                Double_Beep(DBEEPWR, DBEEPWRP);
                USART_RX_Mode(tracking);                // Unterschied Datenempfang GPS/MKCockpit/NMEA
                coldstart = 1;
                rxcount0 = 0;
                rxcount1 = 0;
                servoSetDefaultPos();                           // Ausgangsstellung beider Servos
                if (tracking > TRACKING_MIN)
                        servoInit(SERVO_PERIODE);
                NoTracking_ServosOff();
                USART_Init_Baudrate();
        }
        Jump_Menu(pmenu);
}

/**************************/
/*                       Optionen                                       */
/*      Antennennachführung             */
/*                                                                                              */
/**************************/
void Menu_Tracking_HYST(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_HYSTERESE);
        tmp_val = track_hyst;
        if (Change_Value(&tmp_val, TRACKING_HYST_MIN, TRACKING_HYST_MAX, 7|(1<<V_REPEAT), Displ_Format_Int)) { // pmenu gloabal
                track_hyst = tmp_val;
                eeprom_write_byte(&ep_track_hyst, track_hyst);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

void Menu_Tracking_TXOSD(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_TRACK_TX_OSD_DATA);
        tmp_val = track_tx;
        if (Change_Value(&tmp_val, 0, 1, 3, Displ_track_TX)) { // pmenu global; Senden gibt es nur 0=off, 1=on
                track_tx = tmp_val;
                eeprom_write_byte(&ep_track_tx, track_tx);
                Double_Beep(DBEEPWR, DBEEPWRP);
        }
        Jump_Menu(pmenu);
}

void Menu_Baudrate(void)
{ uint16_t tmp_val;

        Displ_Title(MSG_BAUDRATE);
        tmp_val = baudrate;
        if (Change_Value(&tmp_val, BAUDRATE_MIN, BAUDRATE_MAX, 3, Displ_Baudrate)) { // pmenu global
                baudrate = tmp_val;
                eeprom_write_byte(&ep_baudrate, baudrate);
                Double_Beep(DBEEPWR, DBEEPWRP);
                USART_Init(getBaud(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:       
                case TRACKING_NMEA:                             Menu_Baudrate();
                                                                                                                        break;
        }
}

/**************************/
/*                                                                                              */
/*                      Anzeige GPS                             */
/*                                                                                              */
/**************************/
void Menu_GPS_Display(void)
{ uint8_t scr_sub_menu[SCROLL_MAX_7] = {SCROLL_MAX_7 - 2, MSG_RETURN, MSG_GPS_CALCULATE, MSG_GPS_CURRENT, MSG_GPS_HOME, \
                                                                                                                                                                 MSG_GPS_MISC, MSG_RX_TIME};

        if (tracking == TRACKING_NMEA) {                // Manipulierung der Menüanzeige/-ausführung
                scr_sub_menu[0] = SCROLL_MAX_7 - 3;
                scr_sub_menu[5] = MSG_RX_TIME;
        }
        else
                if (tracking != TRACKING_GPS)   scr_sub_menu[0] = SCROLL_MAX_7 - 4;             // Only show MISC in GPS mode, not NMEA
        Scroll_Menu(scr_sub_menu, 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
        if ((tracking == TRACKING_NMEA) && (gps_display == GPS_MISC))
                pmenu[slen] = RXTimeChr[0];                     // Manipulierung der Menüausführung
        else {
                m_pkt = gps_display;
                gps_disp_clear = 1;                                                             // damit Text "...keine Daten empf..." nach Datenempfang gelöscht wird
                if (gps_display != GPS_MISC)    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);
}

void Menu_GPS_Displ_RX_Time(void)
{
        Displ_Title(MSG_RX_TIME);
        lcdGotoXY(0, 1);
        lcdPuts(Msg(MSG_RX1));
        lcdGotoXY(0, 2);
        lcdPuts(Msg(MSG_RX2));
        Displ_RX_Time();
        // bei Menüpunktmanipulatin TRACKING_NMEA und vorgezogen Menu_GPS_Displ_RX_Time ist Rücksprung real GPS_MISC
        m_pkt = ((tracking == TRACKING_NMEA) && (gps_display == GPS_MISC))? GPS_MISC: GPS_RX_COUNT;
        gps_display = GPS_RX_COUNT;
        if (Short_Enter())                                                               // pmenu global
                pmenu[strlen(pmenu) - 1] = '\0';// Menüpunkt zurück
        gps_display = GPS_DISP_NONE;                     // nach Tastaturabfrage keine Anzeige GPS, sondern normales Menü
        Jump_Menu(pmenu);
}