/** @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_Trx1 EEMEM = 0; // TRX 1 uint8_t ee_Trx2 EEMEM = 0; // TRX 2 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_MemButtonMode 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 // Textspeicher uint8_t ee_Msg1[100] EEMEM; uint8_t ee_Msg2[100] EEMEM; uint8_t ee_Msg3[100] EEMEM; uint8_t ee_Msg4[100] EEMEM; uint8_t ee_Msg5[100] EEMEM; // // /** @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_Trx1, bConfig.Trx1); eeprom_write_byte(&ee_Trx2, bConfig.Trx2); 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_MemButtonMode, bConfig.MemButtonMode); 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.Trx1 = 1; bConfig.Trx2 = 0; bConfig.SidetoneEnabled = 1; bConfig.WpMBpM = 1; bConfig.Reverse = 0; bConfig.MemButtonMode = 1; bConfig.Weight = 50; bConfig.Ratio = 30; bConfig.Memory = 0; bConfig.RiseTime = 6; bConfig.RiseTimeCounter = 8; 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.Trx1 = eeprom_read_byte(&ee_Trx1); bConfig.Trx2 = eeprom_read_byte(&ee_Trx2); bConfig.SidetoneEnabled = eeprom_read_byte(&ee_SidetoneEnabled); bConfig.WpMBpM = eeprom_read_byte(&ee_WpMBpM); bConfig.Reverse = eeprom_read_byte(&ee_Reverse); bConfig.MemButtonMode = eeprom_read_byte(&ee_MemButtonMode); 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< 0) { if(StateButtonPressed == NO_KEY_PRESSED) { StateButtonPressed = KEY_PRESSED_DEBOUNCE; TimerButtonPressed = 0; } if(StateButtonPressed == KEY_PRESSED) { if((bConfig.MemButtonMode) && (ButtonPressed == 5)) { if(TrxButtonPressed == 0) { bConfig.Trx1 = 1; bConfig.Trx2 = 0; } if(TrxButtonPressed == 1) { bConfig.Trx1 = 0; bConfig.Trx2 = 1; } if(TrxButtonPressed == 2) { bConfig.Trx1 = 1; bConfig.Trx2 = 1; } if(TrxButtonPressed == 3) { bConfig.Trx1 = 0; bConfig.Trx2 = 0; } StateButtonPressed = NO_KEY_PRESSED; bMenuCtrl.Update = 1; TrxButtonPressed++; if(TrxButtonPressed > 3) TrxButtonPressed = 0; } else { if(bState.Automatic == 0) { bState.Automatic = 1; StateButtonPressed = NO_KEY_PRESSED; SendMemory(ButtonPressed); } else { StateButtonPressed = NO_KEY_PRESSED; bState.Automatic = 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< 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 == SENDING_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 == SENDING_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 SendString(char *s) { while((*s != 0x00) && (bState.Automatic == 1)) { if(*s != 0x20) { SendChar(*s); DelayMilliSeconds(3*DitMillis); } else if (*s == 0x20) { DelayMilliSeconds(7*DitMillis); } s++; Drehencoder(); CheckPaddles(); CheckButtons(); CheckStraightKey(); if(bState.Automatic == 0) break; } bState.Automatic = 0; } void SendChar(unsigned char c) { switch(c) { // Buchstaben case 'A': SendDit(); SendDah(); break; case 'B': SendDah(); SendDit(); SendDit(); SendDit(); break; case 'C': SendDah(); SendDit(); SendDah(); SendDit(); break; case 'D': SendDah(); SendDit(); SendDit(); break; case 'E': SendDit(); break; case 'F': SendDit(); SendDit(); SendDah(); SendDit(); break; case 'G': SendDah(); SendDah(); SendDit(); break; case 'H': SendDit(); SendDit(); SendDit(); SendDit(); break; case 'I': SendDit(); SendDit(); break; case 'J': SendDit(); SendDah(); SendDah(); SendDah(); break; case 'K': SendDah(); SendDit(); SendDah(); break; case 'L': SendDit(); SendDah(); SendDit(); SendDit(); break; case 'M': SendDah(); SendDah(); break; case 'N': SendDah(); SendDit(); break; case 'O': SendDah(); SendDah(); SendDah(); break; case 'P': SendDit(); SendDah(); SendDah(); SendDit(); break; case 'Q': SendDah(); SendDah(); SendDit(); SendDah(); break; case 'R': SendDit(); SendDah(); SendDit(); break; case 'S': SendDit(); SendDit(); SendDit(); break; case 'T': SendDah(); break; case 'U': SendDit(); SendDit(); SendDah(); break; case 'V': SendDit(); SendDit(); SendDit(); SendDah(); break; case 'W': SendDit(); SendDah(); SendDah(); break; case 'X': SendDah(); SendDit(); SendDit(); SendDah(); break; case 'Y': SendDah(); SendDit(); SendDah(); SendDah(); break; case 'Z': SendDit(); SendDit(); SendDah(); SendDah(); break; // Zahlen case '0': SendDah(); SendDah(); SendDah(); SendDah(); SendDah(); break; case '1': SendDit(); SendDah(); SendDah(); SendDah(); SendDah(); break; case '2': SendDit(); SendDit(); SendDah(); SendDah(); break; case '3': SendDit(); SendDit(); SendDit(); SendDah(); SendDah(); break; case '4': SendDit(); SendDit(); SendDit(); SendDit(); SendDah(); break; case '5': SendDit(); SendDit(); SendDit(); SendDit(); SendDit(); break; case '6': SendDah(); SendDit(); SendDit(); SendDit(); SendDit(); break; case '7': SendDah(); SendDah(); SendDit(); SendDit(); SendDit(); break; case '8': SendDah(); SendDah(); SendDah(); SendDit(); SendDit(); break; case '9': SendDah(); SendDah(); SendDah(); SendDah(); SendDit(); break; // Sonderzeichen case '=': SendDah(); SendDit(); SendDit(); SendDit(); SendDah(); break; case '/': SendDah(); SendDit(); SendDit(); SendDah(); SendDit(); break; case '.': SendDit(); SendDah(); SendDit(); SendDah(); SendDit(); SendDah(); break; case ',': SendDah(); SendDah(); SendDit(); SendDit(); SendDah(); SendDah(); break; case '?': SendDit(); SendDit(); SendDah(); SendDah(); SendDit(); SendDit(); break; case '@': SendDit(); SendDah(); SendDah(); SendDit(); SendDah(); SendDit(); break; } }