/** @file   functions.c
 *  @brief  Diverse Funktionen
 *  @author Tom, DL7BJ
 */

#include "functions.h"

// EEProm Speicher
uint8_t Dummy;
uint8_t ee_Dummy EEMEM = 0x55;               // Dummy for Address 0
uint8_t ee_TRX EEMEM = 0;                    // TRX 1 oder 2 oder beide
uint8_t ee_KeyerMode EEMEM = 1;              // Iambic A, Iambic B oder Ultimatic
uint8_t ee_SidetoneEnabled EEMEM = 1;        // Mithörton eingeschaltet
uint8_t ee_WpMBpM EEMEM = 0;                 // WpM oder BpM Anzeige
uint8_t ee_Reverse EEMEM = 0;                // linkes/rechtes Paddle vertauschen
uint8_t ee_SpeedRatioEnabled EEMEM = 0;      // Ratio von der Geschwindigkeit abhängig
uint8_t ee_Ratio EEMEM = 30;                 // Punkt/Strich Verhältnis 1:3
uint8_t ee_Weight EEMEM = 50;                // Punkt/Strich Gewichtung
uint8_t ee_Memory EEMEM = 0;                 // Punkt/Strich Speicher
uint16_t ee_SidetoneFreq EEMEM = 600;        // Frequenz des Mithörtons
uint8_t ee_WpM EEMEM = 12;                   // Geschwindigkeit WpM
uint8_t ee_RiseTime EEMEM = 5;               // Anstiegszeit Sinuston
uint8_t ee_RiseTimeCounter EEMEM = 5;        // Anzahl Sinusschwingungen für den Anstieg
uint8_t ee_DebounceTime EEMEM = 6;           // Entprellzeit für Straight Key Eingang
//
//
/** @fn     void DelayMilliSeconds(uint16_t ms)
 *  @brief  Zeitschleife von 1-65535 Millisekunden
 *  @param  Anzahl Millisekunden
 *  @return none
 */
void DelayMilliSeconds(uint16_t ms)
{
    volatile static uint16_t ctr;
    ResetMilliSeconds();
    do
    {
        ATOMIC_BLOCK(ATOMIC_FORCEON)
        {
            ctr = t_delayms;
        }
        CheckPaddles();
    } while (ctr < ms);
}
/** @fn     uint16_t GetMilliSeconds(void)
 *  @brief  Zäherwert für Zeitschleifen auslesen
 *  @param  none
 *  @return Millisekunden
 */
uint16_t GetMilliSeconds(void)
{
    volatile static uint16_t ctr;
    ATOMIC_BLOCK(ATOMIC_FORCEON)
    {
        ctr = t_delayms;
    }
    return ctr;
}
/** @fn     void ResetMilliSeconds(void)
 *  @brief  Setzt den Millisekundenzähler für Zeitschleifen auf 0
 *  @param  none
 *  @return none
 */
void ResetMilliSeconds(void)
{
    ATOMIC_BLOCK(ATOMIC_FORCEON)
    {
        t_delayms = 0;
    } 
}
/** @fn     void IntEnable(void) 
 *  @brief  Register wieder herstellen und Interrupts erlauben
 *  @param  none
 *  @return none
 */
void IntEnable(void)
{
  SREG = sreg_tmp;
  sei();
}
/** @fn     void IntDisable(void)
 *  @brief  Register sichern und Interrupts verbieten
 *  @param  none
 *  @return none
 */
void IntDisable(void)
{
  sreg_tmp = SREG;
  cli();
}
/** @fn     void WriteEEprom(void)
 *  @brief  Akt. Einstellungen in EEPROM schreiben
 *  @param  none
 *  @return none
 */
void WriteEEprom(void)
{
    IntDisable();
    eeprom_write_byte(&ee_Dummy,0x55);
    eeprom_write_byte(&ee_WpM, bConfig.WpM);
    eeprom_write_byte(&ee_KeyerMode, bConfig.KeyerMode);
    eeprom_write_word(&ee_SidetoneFreq, bConfig.SidetoneFreq);
    eeprom_write_byte(&ee_TRX, bConfig.TRX);
    eeprom_write_byte(&ee_SidetoneEnabled, bConfig.SidetoneEnabled);
    eeprom_write_byte(&ee_WpMBpM, bConfig.WpMBpM);
    eeprom_write_byte(&ee_Reverse, bConfig.Reverse);
    eeprom_write_byte(&ee_SpeedRatioEnabled, bConfig.SpeedRatioEnabled);
    eeprom_write_byte(&ee_Weight, bConfig.Weight);
    eeprom_write_byte(&ee_Ratio, bConfig.Ratio);
    eeprom_write_byte(&ee_Memory, bConfig.Memory);
    eeprom_write_byte(&ee_RiseTime, bConfig.RiseTime);
    eeprom_write_byte(&ee_RiseTimeCounter, bConfig.RiseTimeCounter);
    eeprom_write_byte(&ee_DebounceTime, bConfig.DebounceTime);
    IntEnable();
}
/** @fn     void ReadEEpromWpM(void)
 *  @brief  Gespeicherte Einstellung für die Geschwindigkeit aus EEprom lesen
 *  @param  none
 *  @return none
 */
void ReadEEpromWpM(void)
{
    IntDisable();
    bConfig.WpM = eeprom_read_byte(&ee_WpM);
    IntEnable();
}
/** @fn     void WriteEEpromWpM(void)
 *  @brief  Akt. Einstellung für die Geschwindigkeit in EEprom schreiben
 *  @param  none
 *  @return none
 */
void WriteEEpromWpM(void)
{
    IntDisable();
    eeprom_write_byte(&ee_WpM, bConfig.WpM);
    IntEnable();
}
/** @fn     void SetEEprom(void)
/** @brief  Standardeinstellungen (bei neuem Controller)
 *
 *          Wird ein neuer Controller verwendet, gibt es keine 
 *          Einstellungswerte im EEprom. Diese Funktion schreibt
 *          die initialen Werte in das EEprom. Wird sehr selten
 *          benötigt ;-)
 *
 *  @param  none
 *  @return none
 */
void SetEEprom(void)
{
    Dummy = 0x55;
    bConfig.WpM = 15;
    bConfig.KeyerMode = 2;
    bConfig.SidetoneFreq = 600;
    bConfig.TRX = 1;
    bConfig.SidetoneEnabled = 1;
    bConfig.WpMBpM = 1;
    bConfig.Reverse = 0;
    bConfig.SpeedRatioEnabled = 0;
    bConfig.Weight = 50;
    bConfig.Ratio = 30;
    bConfig.Memory = 0;
    bConfig.RiseTime = 5;
    bConfig.RiseTimeCounter = 5;
    bConfig.DebounceTime = 5;
    WriteEEprom();
}
/** @fn     void ReadEEprom(void) 
 *  @brief  Einstellungen aus dem EEprom lesen
 *  @param  none
 *  @return none
 */
void ReadEEprom(void)
{
    IntDisable();
    Dummy = eeprom_read_byte(&ee_Dummy);
    IntEnable();
    if(Dummy != 0x55)
    {
        SetEEprom();
    }
    IntDisable();
    bConfig.WpM = eeprom_read_byte(&ee_WpM);
    bConfig.KeyerMode = eeprom_read_byte(&ee_KeyerMode);
    bConfig.SidetoneFreq = eeprom_read_word(&ee_SidetoneFreq);
    bConfig.TRX = eeprom_read_byte(&ee_TRX);
    bConfig.SidetoneEnabled = eeprom_read_byte(&ee_SidetoneEnabled);
    bConfig.WpMBpM = eeprom_read_byte(&ee_WpMBpM);
    bConfig.Reverse = eeprom_read_byte(&ee_Reverse);
    bConfig.SpeedRatioEnabled = eeprom_read_byte(&ee_SpeedRatioEnabled);
    bConfig.Ratio = eeprom_read_byte(&ee_Ratio);
    bConfig.Weight = eeprom_read_byte(&ee_Weight);
    bConfig.Memory = eeprom_read_byte(&ee_Memory);
    bConfig.RiseTime = eeprom_read_byte(&ee_RiseTime);
    bConfig.RiseTimeCounter = eeprom_read_byte(&ee_RiseTimeCounter);
    bConfig.DebounceTime = eeprom_read_byte(&ee_DebounceTime);
    IntEnable();
}
/** @fn     void SerialWriteChar(unsigned char data)
 *  @brief  Ein Zeichen über serielle Schnittstelle ausgeben
 *  @param  Zeichen 
 *  @return none
 */
void SerialWriteChar(unsigned char data)
{
    while(!(UCSR0A & (1<<UDRE0)));
    UDR0 = data;
}
/** @fn     void SerialWriteString(unsigned char *s)
 *  @brief  Eine Zeichenkette über serielle Schnittstelle ausgeben
 *  @param  Zeiger auf Zeichenkette, die mit 0x00 abgeschlossen sein muss
 *  @return none
 */
void SerialWriteString(char *s)
{
    while(*s != 0x00)
        SerialWriteChar(*s++);
}
/** @fn     void SidetoneOn(void) 
 *  @brief  Mithörton einschalten
 *  @param  none
 *  @return none
 */
void SidetoneOn(void)
{
    bState.SidetoneOff = 0;
    StateRiseTime = bConfig.RiseTime;
    StateRiseTimeCounter = 0;
    icnt = 0;
    sbi(TIMSK1,OCIE1A);
}
/** @fn     void SidetoneOff(void) 
 *  @brief  Mithörtone ausschalten
 *  @param  none
 *  @return none
 */
void SidetoneOff(void)
{
    bState.SidetoneOff = 1;
    StateRiseTime = 0;
    StateRiseTimeCounter = 0;
}
/** @fn     void SidetoneDisable(void)
/*  @brief  Audioverstärker abschalten
 *  @param  none
 *  @return none
 */
void SidetoneDisable(void)
{
    bConfig.SidetoneEnabled = 0;
    cbi(PORTB,AUDIO_EN);
}
/** @fn     void SidetoneEnable(void)
 *  @brief  Audioverstärker einschalten
 *  @param  none
 *  @return none
 */
void SidetoneEnable(void)
{
    bConfig.SidetoneEnabled = 1;
    sbi(PORTB,AUDIO_EN);
}
/** @fn     void TXKey(uint8_t State)
 *  @brief  Gibt ein Symbol aus
 *
 *          Je nach Einstellung wird ein oder beide Transceiver
 *          getastet oder nur der Mithörton ausgegeben.
 *
 *  @param  State - Bitfeld für Transceiver und Tonausgabe
 *  @return none
 */
void TXKey(uint8_t State)
{
    if((State) && (bState.KeyState == 0))
    {
        if(bState.KeyTX)
        {
            SidetoneOn();
            sbi(PORTC,MORSE_LED);
            bState.KeyState = 1;
        }
    }
    else
    {
        if((State == 0) && (bState.KeyState))
        {
            if(bState.KeyTX)
            {
                SidetoneOff();
                cbi(PORTC,MORSE_LED);
            }
            bState.KeyState = 0;
        }
    }
}
/** @fn     void CheckStraightKey(void)
 *  @brief  Fragt die Handtasteneingänge ab und gibt das 
 *          entsprechende Symbol aus. Bei der Handtaste 
 *          findet über einen Timer noch eine Software 
 *          Entprellung statt
 *  @param  none
 *  @return none
 */
void CheckStraightKey(void)
{
    if(PIND & (1<<STRAIGHT_KEY))
    {
        if(bState.SendStatus == SENDING_NOTHING)
            TXKey(0);
        StateStraightKeyPressed = NO_KEY_PRESSED;
    } else {
        if(StateStraightKeyPressed == NO_KEY_PRESSED)
        {
            StateStraightKeyPressed = KEY_PRESSED_DEBOUNCE;
            TimerStraightKeyPressed = 0;
        }
        if(StateStraightKeyPressed == KEY_PRESSED)
        {
            if(bState.SendStatus == SENDING_NOTHING)
                TXKey(1);
        }
    }
}
/** @fn     void CheckPaddles(void)
 ** @brief  Diese Funktion prüft, ob ein Paddle betätigt wurde.
 **
 **         Wenn dies der Fall war, ist das jeweilige Statusbit gesetzt
 **         und die Funktion für die Ausgabe des entsprechendem Symbol
 **         wird aufgerufen.
 **
 ** @param  none
 ** @return none
*/
void CheckPaddles(void)
{
    CheckDitPaddle();
    CheckDahPaddle();

    // Wenn Paddle betätigt wurde, 
    if(bState.SendStatus == SENDING_NOTHING)
    {
        if(bState.DitPressed || bState.DahPressed)
        {
            if(bState.DitPressed && !bState.DahPressed)
                SendDit();
            else if(bState.DahPressed && !bState.DitPressed)
                SendDah();
            else if(bState.DahPressed && bState.DitPressed)
                SendIambic();
        }
    }
}
/** @fn     void CheckDitPaddle(void)
 *  @brief  Prüfen, ob das Punkt Paddle betätigt wurde.
 *
 *          Ist dies der Fall, wird das Statusbit gesetzt.Wurde in den 
 *          Einstellungen der Reverse Mode aktiviert, werden in der 
 *          Abfrage die Paddle vertauscht.
 *
 *  @param  none
 *  @return none
*/
void CheckDitPaddle(void)
{
    uint8_t pinvalue = 0;

    if(PaddleMode == PADDLE_NORMAL)
        pinvalue = PIND & (1<<LEFT_PADDLE);
    else
        pinvalue = PIND & (1<<RIGHT_PADDLE);

    if((pinvalue == 0) && ((!(bState.SendStatus == SENDING_DIT)) || (bState.SendStatus == SENDING_NOTHING)))
    {
        bState.DitPressed = 1;
    }
    // Wenn Punkt/Strich Speicher aktiviert ist, das Symbol merken, wenn es nicht identisch ist 
    if((pinvalue == 0) && (!(bState.SendStatus == SENDING_DIT)) && (bConfig.Memory == 1))
        bState.DitPressed = 1;

}
/** @fn     void CheckDahPaddle(void)
 *  @brief  Prüfen, ob das Strich Paddle betätigt wurde.
 *
 *          Ist dies der Fall, wird das Statusbit gesetzt. Wurde in den 
 *          Einstellungen der Reverse Mode aktiviert, werden in der 
 *          Abfrage die Paddle vertauscht.
 *
 *  @param  none
 *  @return none
*/
void CheckDahPaddle(void)
{
    uint8_t pinvalue = 0;

    if(PaddleMode == PADDLE_NORMAL)	// no reverse paddle
        pinvalue = PIND & (1<<RIGHT_PADDLE);
    else
        pinvalue = PIND & (1<<LEFT_PADDLE); // reverse paddle

    // Das Symbol nur merken, wenn nicht gerade eines ausgegeben wird oder gar nichts ausgegeben wird
    if((pinvalue == 0) && ((!(bState.SendStatus == SENDING_DAH)) || (bState.SendStatus == SENDING_NOTHING)))
    {
        bState.DahPressed = 1;
    }
    // Wenn Punkt/Strich Speicher aktiviert ist, das Symbol merken, wenn es nicht identisch ist
    if((pinvalue == 0) && (!(bState.SendStatus == SENDING_DAH)) && (bConfig.Memory == 1))
        bState.DahPressed = 1;
}
/** @fn     void SetRatio(void)
 *  @brief  Berechnung der Zeitdauer für Punkt und Strich
 *
 *          Die Länge eines Symbols ist abhängig von der
 *          eingestellten Geschwindigkeit. Intern wird immer
 *          mit Wörtern pro Minute gerechnet. Das normale
 *          Punkt/Strich Verhältnis ist 1:3. Dies kann durch
 *          den Parameter Ratio in den Einstellungen verändert
 *          werden. Wird ein Korrekturfaktor angegeben, kann
 *          das Ratio über eine Tabelle in Abhängigkeit der
 *          Geschwindigkeit bis zu 1:2.0 verändert werden.
 *
 *  @param  none
 *  @return none
 */
void SetRatio(void)
{
    DitMillis = 1200 / WpM;
    if(bConfig.SpeedRatioEnabled)
        DahMillis = DitMillis * (float)(bState.WpMCorrectFactor / 10);
    else
        DahMillis = DitMillis * (float)(bConfig.Ratio/10);
}
/** @fn     void GetWpMCorrectFactor(void)
 *  @brief  Ermittelt den Korrekturfaktor für das Ratio
 *  param   none
 *  return  none
 */
void GetWpMCorrectFactor(void)
{
    bState.WpMCorrectFactor = 30;
    if(WpM > 20)
        bState.WpMCorrectFactor = 28;

}
void SetWeight(void)
{
    DitMillis = 1200/WpM;
    DahMillis = 3 * DitMillis;
    SpcMillis = 1200/WpM;
    DitMillis = (bConfig.Weight/50.0) * DitMillis;
    DahMillis = (bConfig.Weight/50.0) * DahMillis;
    if(bConfig.Weight < 50)
        SpcMillis = SpcMillis + (SpcMillis - DitMillis);
    else
        SpcMillis = SpcMillis - (DitMillis - SpcMillis);
}
/** @fn     void SendSymbol(uint8_t Dit)
 *  @brief  Symbol senden
 *  @param  Dit = 1, wenn Symbol ein Punkt ist
 *  @return none
 */
void SendSymbol(uint8_t Dit)
{
    static uint16_t ticks;     // Länge des Symbols
    if(Dit)
        ticks = DitMillis;
    else 
        ticks = DahMillis;
    t_elementlength = 0;

    TXKey(1);
    DelayMilliSeconds(ticks);
    bState.SendStatus = SENDING_SPC;
    TXKey(0);
    DelayMilliSeconds(SpcMillis);
}

/** @fn     void SendDit(void)
 *  @brief  Gibt einen Punkt aus
 *  @param  none
 *  @return none
 */
void SendDit(void)
{
    if((bState.SendStatus == NOTHING) || (bState.SendStatus == SENDING_DAH))
    {
        bState.DitPressed = 0;
        bState.SendStatus = SENDING_DIT;
        SendSymbol(DIT);
        bState.SendStatus = SENDING_NOTHING;
        bState.LastSymbolWasDit = 1;
    }
    if(bConfig.Memory == 0)
        bState.DitPressed = 0;
}
/** @fn     void SendDah(void)
 *  @brief  Gibt einen Strich aus
 *  @param  none
 *  @return none
*/
void SendDah(void)
{
    if((bState.SendStatus == NOTHING) || (bState.SendStatus == SENDING_DIT))
    {
        bState.DahPressed = 0;
        bState.SendStatus = SENDING_DAH;
        SendSymbol(DAH);
        bState.SendStatus = SENDING_NOTHING;
        bState.LastSymbolWasDit = 0;
    }
    if(bConfig.Memory == 0)
        bState.DahPressed = 0;
}
/** @fn     void SendIambic(void)
 *  @brief  Wenn beide Paddle betätigt sind, wird alternierend
 *          ein Punkt und Strich ausgegeben.
 *
 *          Beim Iambic B Mode und Ultimatic Mode wird gegebenenfalls 
 *          noch ein gegensätzliches Zeichen des zuletzt betätigten Paddle 
 *          angefügt. Erläuterung und Timing siehe Dokumentation.
 *
 *  @param  none
 *  @return none
*/
void SendIambic(void)
{
    bState.DahPressed = 0;
    bState.DitPressed = 0;
    if(bState.LastSymbolWasDit)
    {
        SendDah();
        if(bConfig.KeyerMode == IAMBIC_B && !bState.DahPressed && !bState.DitPressed)
        {
            SendDit();
        } else {
            if(bConfig.KeyerMode == ULTIMATIC)
            {
                while(bState.DahPressed)
                {
                    bState.DitPressed = 0;
                    bState.DahPressed = 0;
                    SendDah();
                }
            }
        } 
    } else {
        SendDit();
        if(bConfig.KeyerMode == IAMBIC_B && !bState.DitPressed && !bState.DahPressed)
        {
            SendDah();
        } else {
            if(bConfig.KeyerMode == ULTIMATIC)
            {
                while(bState.DitPressed)
                {
                    bState.DitPressed = 0;
                    bState.DahPressed = 0;
                    SendDit();
                }
            }
        }
    }
}
/** @fn     void SetFrequency(uint16_t f)
 *  @brief  Verändert die Frequenz des Mithörtons
 *
 *          Durch die Anpassung des Timers 1 für das 
 *          Laden der Werte der Sinuskurve wird die 
 *          Tonhöhe des Mithörtons verändert.
 *  @param  Frequenz des Mithörtons in Hz
 *  @return none
 */
void SetFrequency(uint16_t f)
{
    IntDisable();
    OCR1A = (F_CPUPRESIN / f) - 1;
    IntEnable();
}
/** @fn     void Tone(uint16_t f, uint8_t duration)
 *  @brief  Ausgabe eines Tons mit Dauer und Frequenz
 *  @param  f           - Frequenz des Tons
 *          duration    - Dauer des Tons
 *  @return none
 */
void Tone(uint16_t f, uint8_t duration)
{
    SetFrequency(f);
    SidetoneOn();
    DelayMilliSeconds(duration);
    SidetoneOff();
    SetFrequency(bConfig.SidetoneFreq);
}
/** @fn     void Boop(void)
 *  @brief  Boop Ton ausgeben
 *  @param  none
 *  @return none
 */
void Boop(void)
{
    Tone(600,100);
}
/** @fn     void Beep(void)
 *  @brief  Beep Ton ausgeben
 *  @param  none
 *  @return none
 */
void Beep(void)
{
    Tone(1200,100);
}
/** @fn     void BeepBoop(void)
 *  @brief  BeepBoop Doppelton ausgeben
 *  @param  none
 *  @return none
 */
void BeepBoop(void)
{
    DelayMilliSeconds(10);
    Beep();
    DelayMilliSeconds(100);
    Boop();
}

void SendChar(unsigned char c)
{
    switch(c)
    {
        // Buchstaben
/*
        case 'A': SendDit(AUTO); SendDah(AUTO); break;
        case 'B': SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case 'C': SendDit(AUTO); SendDah(AUTO); SendDit(AUTO); SendDah(AUTO); break;
        case 'D': SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case 'E': SendDit(AUTO); break;
        case 'F': SendDit(AUTO); SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case 'G': SendDah(AUTO); SendDah(AUTO); SendDit(AUTO); break;
        case 'H': SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case 'I': SendDit(AUTO); SendDit(AUTO); break;
        case 'J': SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); SendDah(AUTO); break;
        case 'K': SendDah(AUTO); SendDit(AUTO); SendDah(AUTO); break;
        case 'L': SendDit(AUTO); SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case 'M': SendDah(AUTO); SendDah(AUTO); break;
        case 'N': SendDah(AUTO); SendDit(AUTO); break;
        case 'O': SendDah(AUTO); SendDah(AUTO); SendDah(AUTO); break;
        case 'P': SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); SendDit(AUTO); break;
        case 'Q': SendDah(AUTO); SendDah(AUTO); SendDit(AUTO); SendDah(AUTO); break;
        case 'R': SendDit(AUTO); SendDah(AUTO); SendDit(AUTO); break;
        case 'S': SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case 'T': SendDah(AUTO); break;
        case 'U': SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); break;
        case 'V': SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); break;
        case 'W': SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); break;
        case 'X': SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); break;
        case 'Y': SendDah(AUTO); SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); break;
        case 'Z': SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); break;
        // Zahlen
        case '0': SendDah(AUTO); SendDah(AUTO); SendDah(AUTO); SendDah(AUTO); SendDah(AUTO); break;
        case '1': SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); SendDah(AUTO); SendDah(AUTO); break;
        case '2': SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); break;
        case '3': SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); break;
        case '4': SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); break;
        case '5': SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case '6': SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case '7': SendDah(AUTO); SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case '8': SendDah(AUTO); SendDah(AUTO); SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case '9': SendDah(AUTO); SendDah(AUTO); SendDah(AUTO); SendDah(AUTO); SendDit(AUTO); break;
        // Sonderzeichen
        case '=': SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); break;
        case '/': SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); SendDit(AUTO); break;
        case '.': SendDit(AUTO); SendDah(AUTO); SendDit(AUTO); SendDah(AUTO); SendDit(AUTO); SendDah(AUTO); break;
        case ',': SendDah(AUTO); SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); break;
        case '?': SendDit(AUTO); SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); SendDit(AUTO); SendDit(AUTO); break;
        case '@': SendDit(AUTO); SendDah(AUTO); SendDah(AUTO); SendDit(AUTO); SendDah(AUTO); SendDit(AUTO); break;
  */
    }
}

