/** @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< 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; */ } }