|
|
|
/** @file functions.c
|
|
|
|
* @brief Diverse Funktionen
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "functions.h"
|
|
|
|
|
|
|
|
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; ///< Funktion des ersten Tasters (MEM5)
|
|
|
|
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 ms Anzahl Millisekunden
|
|
|
|
* @retval 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ählerwert für Zeitschleifen auslesen
|
|
|
|
|
|
|
|
* @param none
|
|
|
|
* @retval 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
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void ResetMilliSeconds(void)
|
|
|
|
{
|
|
|
|
ATOMIC_BLOCK(ATOMIC_FORCEON)
|
|
|
|
{
|
|
|
|
t_delayms = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** @fn void IntEnable(void)
|
|
|
|
* @brief Register wieder herstellen und Interrupts erlauben
|
|
|
|
|
|
|
|
* @param none
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void IntEnable(void)
|
|
|
|
{
|
|
|
|
SREG = sreg_tmp;
|
|
|
|
sei();
|
|
|
|
}
|
|
|
|
/** @fn void IntDisable(void)
|
|
|
|
* @brief Register sichern und Interrupts verbieten
|
|
|
|
|
|
|
|
* @param none
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void IntDisable(void)
|
|
|
|
{
|
|
|
|
sreg_tmp = SREG;
|
|
|
|
cli();
|
|
|
|
}
|
|
|
|
/** @fn void WriteEEprom(void)
|
|
|
|
* @brief Akt. Einstellungen in EEPROM schreiben
|
|
|
|
|
|
|
|
* @param none
|
|
|
|
* @retval 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
|
|
|
|
* @retval 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
|
|
|
|
* @retval 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
|
|
|
|
* @retval 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();
|
|
|
|
SetStandardMsg();
|
|
|
|
for(uint8_t i = 1; i < 6; i++)
|
|
|
|
WriteMsgEEprom(i);
|
|
|
|
}
|
|
|
|
/** @fn void ReadEEprom(void)
|
|
|
|
* @brief Einstellungen aus dem EEprom lesen
|
|
|
|
|
|
|
|
* @param none
|
|
|
|
* @retval 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 data Zeichen, das seriell ausgegeben wird
|
|
|
|
* @retval 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
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void SerialWriteString(char *s)
|
|
|
|
{
|
|
|
|
while(*s != 0x00)
|
|
|
|
SerialWriteChar(*s++);
|
|
|
|
}
|
|
|
|
/** @fn void SidetoneOn(void)
|
|
|
|
* @brief Mithörton einschalten
|
|
|
|
*
|
|
|
|
* @param none
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void SidetoneOn(void)
|
|
|
|
{
|
|
|
|
bState.SidetoneOff = 0;
|
|
|
|
StateRiseTime = bConfig.RiseTime;
|
|
|
|
StateRiseTimeCounter = 0;
|
|
|
|
icnt = 0;
|
|
|
|
sbi(TIMSK1,OCIE1A);
|
|
|
|
}
|
|
|
|
/** @fn void SidetoneOff(void)
|
|
|
|
* @brief Mithörton ausschalten
|
|
|
|
*
|
|
|
|
* @param none
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void SidetoneOff(void)
|
|
|
|
{
|
|
|
|
bState.SidetoneOff = 1;
|
|
|
|
StateRiseTime = 0;
|
|
|
|
StateRiseTimeCounter = 0;
|
|
|
|
}
|
|
|
|
/** @fn void SidetoneDisable(void)
|
|
|
|
* @brief Audioverstärker abschalten
|
|
|
|
*
|
|
|
|
* @param none
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void SidetoneDisable(void)
|
|
|
|
{
|
|
|
|
bConfig.SidetoneEnabled = 0;
|
|
|
|
cbi(PORTB,AUDIO_EN);
|
|
|
|
}
|
|
|
|
/** @fn void SidetoneEnable(void)
|
|
|
|
* @brief Audioverstärker einschalten
|
|
|
|
*
|
|
|
|
* @param none
|
|
|
|
* @retval 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
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void TXKey(uint8_t State)
|
|
|
|
{
|
|
|
|
if((State) && (bState.KeyState == 0))
|
|
|
|
{
|
|
|
|
if(bState.KeyTX)
|
|
|
|
{
|
|
|
|
SidetoneOn();
|
|
|
|
sbi(PORTC,MORSE_LED);
|
|
|
|
if(bConfig.Trx1)
|
|
|
|
sbi(PORTC,TRX1);
|
|
|
|
if(bConfig.Trx2)
|
|
|
|
sbi(PORTC,TRX2);
|
|
|
|
bState.KeyState = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if((State == 0) && (bState.KeyState))
|
|
|
|
{
|
|
|
|
if(bState.KeyTX)
|
|
|
|
{
|
|
|
|
SidetoneOff();
|
|
|
|
cbi(PORTC,MORSE_LED);
|
|
|
|
if(bConfig.Trx1)
|
|
|
|
cbi(PORTC,TRX1);
|
|
|
|
if(bConfig.Trx2)
|
|
|
|
cbi(PORTC,TRX2);
|
|
|
|
}
|
|
|
|
bState.KeyState = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** @fn void CheckButtons(void)
|
|
|
|
* @brief Fragt die Taster ab und löst entsprechende Funktion aus
|
|
|
|
*
|
|
|
|
* @todo Für die Transceiverumschaltung sollte noch eine Einstellung
|
|
|
|
* hinzugefügt werden, die hier die Option bietet, nur zwischen
|
|
|
|
* TRX1 und TRX2 hin- und her zuschalten, so dass beide TRX an
|
|
|
|
* (SO2R) nicht möglich ist.
|
|
|
|
*
|
|
|
|
* @param none
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void CheckButtons(void)
|
|
|
|
{
|
|
|
|
static uint8_t ButtonPressed;
|
|
|
|
static uint8_t TrxButtonPressed = 0;
|
|
|
|
ButtonPressed = 0;
|
|
|
|
if(!(PINB & (1<<MEM5)))
|
|
|
|
ButtonPressed = 5;
|
|
|
|
if(!(PINC & (1<<MEM4)))
|
|
|
|
ButtonPressed = 4;
|
|
|
|
if(!(PIND & (1<<MEM3)))
|
|
|
|
ButtonPressed = 3;
|
|
|
|
if(!(PIND & (1<<MEM2)))
|
|
|
|
ButtonPressed = 2;
|
|
|
|
if(!(PIND & (1<<MEM1)))
|
|
|
|
ButtonPressed = 1;
|
|
|
|
if(ButtonPressed > 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 eine Entprellung statt
|
|
|
|
*
|
|
|
|
* @param none
|
|
|
|
* @retval 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)
|
|
|
|
{
|
|
|
|
bState.Automatic = 0;
|
|
|
|
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 entsprechenden Symbols
|
|
|
|
** wird aufgerufen.
|
|
|
|
**
|
|
|
|
** @param none
|
|
|
|
** @retval none
|
|
|
|
*/
|
|
|
|
void CheckPaddles(void)
|
|
|
|
{
|
|
|
|
CheckDitPaddle();
|
|
|
|
CheckDahPaddle();
|
|
|
|
|
|
|
|
// Wenn Paddle betätigt wurde,
|
|
|
|
if(bState.SendStatus == SENDING_NOTHING)
|
|
|
|
{
|
|
|
|
if(bState.DitPressed || bState.DahPressed)
|
|
|
|
{
|
|
|
|
bState.Automatic = 0;
|
|
|
|
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
|
|
|
|
* @retval 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
|
|
|
|
* @retval 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.
|
|
|
|
*
|
|
|
|
* @param none
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void SetRatio(void)
|
|
|
|
{
|
|
|
|
DitMillis = 1200 / WpM;
|
|
|
|
DahMillis = DitMillis * (float)(bConfig.Ratio/10);
|
|
|
|
}
|
|
|
|
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
|
|
|
|
* @retval 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
|
|
|
|
* @retval 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
|
|
|
|
* @retval 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
|
|
|
|
* @retval 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 f Frequenz des Mithörtons in Hz
|
|
|
|
* @retval 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
|
|
|
|
* @param duration Dauer des Tons
|
|
|
|
* @retval 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
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void Boop(void)
|
|
|
|
{
|
|
|
|
Tone(600,100);
|
|
|
|
}
|
|
|
|
/** @fn void Beep(void)
|
|
|
|
* @brief Beep Ton ausgeben
|
|
|
|
|
|
|
|
* @param none
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void Beep(void)
|
|
|
|
{
|
|
|
|
Tone(1200,100);
|
|
|
|
}
|
|
|
|
/** @fn void BeepBoop(void)
|
|
|
|
* @brief BeepBoop Doppelton ausgeben
|
|
|
|
|
|
|
|
* @param none
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
void BeepBoop(void)
|
|
|
|
{
|
|
|
|
DelayMilliSeconds(10);
|
|
|
|
Beep();
|
|
|
|
DelayMilliSeconds(100);
|
|
|
|
Boop();
|
|
|
|
}
|
|
|
|
/** @fn void SendString(char *s)
|
|
|
|
* @brief Gibt eine Zeichenkette als Morsecode aus
|
|
|
|
*
|
|
|
|
* Wenn die Zeichenkette ein Leerzeichen enthält, wird dieses als Pause
|
|
|
|
* zwischen zwei Wörtern interpretiert und eine Pause der Länge von 7
|
|
|
|
* Dits (in Abhängigkeit der eingestellten Geschwindigkeit) wird eingefügt
|
|
|
|
* Zwischen einzelnen Zeichen wird eine Pause von 3 Dits eingefügt
|
|
|
|
*
|
|
|
|
* @todo Für die Zeichenausgabe der Textspeicher könnte hier noch die Beachtung
|
|
|
|
* des eingestellten Ratios und der Gewichtung zugefügt werden.
|
|
|
|
*
|
|
|
|
* @param s Zeiger auf die Zeichenkette
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
/** @fn void SendChar(unsigned char c)
|
|
|
|
* @brief Gibt ein Zeichen aus
|
|
|
|
*
|
|
|
|
* Mit dieser Symboltabelle werden die Zeichen
|
|
|
|
* der Textspeicher gesendet
|
|
|
|
*
|
|
|
|
* @param c Zeichen, das Ausgegeben wird
|
|
|
|
* @retval none
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|