Home » Amateurfunk » Software » Morsen » MorseGenerator

MorseGenerator

Siehe auch morse.h und morse.cpp.

Aufgabe der Klasse MorseGenerator:

Die Morse-Tabelle 

Zunächst muß das Programm die Kodierung der Morsezeichen kennen.

Wenn ich für einen PIC programmieren würde, dann würde ich die Morsezeichen als Bitmuster speichern. Ich programmiere hier aber als Desktop, also lege ich auf Speicherplatz nicht so großen Wert.

In codes wird's gespeichert:

Hash<QString, QString> codes;            // e.g. "-.."

Ein QHash ist sozusagen ein assoziatives Array, also ein Array mit Strings als Index. So kommen die Daten rein:

store("a",   ".-");
store("b",   "-...");
store("c",   "-.-.");
//...
store("KA",  "-.-.-"); // Spruchanfang
store("BT",  "-..-."); // Pause
store("AR",  ".-.-."); // Spruchende

// ...
void GenerateMorse::store(const QString &sign, const QString &code)
{
    if (codes.contains(sign))
        qFatal("'%s' already defined as '%s'",
            qPrintable(sign), qPrintable(codes[sign]) );
    codes[sign] = code;
}

Womit man auch sogleich sehen konnte, wie man mit so einem QHash umgeht.

Umwandlung Buchstaben nach Morse 

Um ein Buchstaben in die Morse-Sequenz umzuwandeln, müssen wir nur nachschauen, ob für den Buchstaben ein Eintrag existiert:

void GenerateMorse::append(const QString &str, bool addSpace)
{
    if (codes.contains(str)) {
        appendMorse(codes[str], str);
        return;
    }
    // ...

In der Praxis ist die Funktion noch etwas komplexer, da man ihr auch komplette Strings übergeben kann:

morse->append("73 de dh3hs");

Nun habe ich dann also sowas wie "-.", also Punkte und Striche. Was mache ich damit? Direkt morsen kann ich das nicht. Ich muß es noch in eine Folge von Pulsen bzw. Pausen umwandeln.

Das erlegigt die Funktion appendMorse(). Sie bekommt einen String, der nur die drei Zeichen "-", "." und " " enthalten darf. Das sind Punkt, Strich, und der Leerraum zwischen zwei Wörtern.

Daraus erstellt sie eine Liste von Integers, QList<int> morse genannt, in der die zu gebenden Pulse als positive Längen und die zu wartenden Pausen als negative Längen hineingeschrieben werden.

Generell gibt es fünf unterschiedliche Längen:

Damit sichd die Werte alle Unterschreiten, nehme ich für die Pausen einfach negative Einheiten. Heraus kommt 1, 3, -1, -3, -7. Und nun drösele ich "-. ." auf in die Sequenz

Abspielen der Morsezeichen 

Der MorseGenerator kann diese Puls/Längeninformation nun auch abspielen. Nunja, wirklich abspielen tut er sie nicht, er macht das, was viele Qt-Objekte tun: er schickt zum richtigen Zeitpunkt Signale an beliebige Empfänger.

Bevor es aber an die Signale geht, müssen die Längeneinheiten in Zeiteinheiten, gemessen in Millisekunden, umgerechnet werden.

Dafür ist die Methode MorseGenerator::playNext(). Sie holt sich den jeweils nächsten Eintrag aus der QList morse, und berechnet seine Länge durch 1200 / wpm. Wer wissen will, wie ich auf diese Funktion komme, mag sich den Source-Code ansehen. Dort befindet sich ein entsprechender Kommentar mit der Ableitung.

wpm steht übrigens für "Words per Minute", bezogen auf den Morse-Code für das Wort "paris " (einschließlich Leerzeichen!).

Nun kann es sein, das man bei hohen WPM-Werten nicht so schnell nachkommt. Also wäre es doch nett, wenn man die Pause zwischen zwei Zeichen erhöhen könnte. Oder bei 75 WPM ist der Punkt so kurz, das man ihn kaum hört. Da wäre es nett, wenn man ihn künstlich etwas länger machen könnte.

Und deswegen hat jede der 5 Längen eine eigenen Faktor zum Verlängern (wenn > 1.0) oder Verkürzen (wenn < 1.0). Diese setzt man mit

und natürlich gibt's auch noch

Alle diese Methoden sind übrigens keine normalen Methoden, sondern Slots eines QObject. Man kann sie daher einfach an das valueChanged()-Signal eines QDoubleSpinBox oder einem QSlider hängen.

Werden diese Faktoren auf Werte ungleich 1.0 gesetzt, dann ändert sich natürlich die effektive WPM-Geschwindigkeit. Die kann man aber, wieder bezogen auf "paris ", mit getWpm() abrufen.

Wenn schließlich die Zeiten klar sind, erzeigt MorseGenerator die folgenden Signale zum richtigen Zeitpunkt:

Die ersten beiden Signale tun im Prinzip dasselbe. Das obere wird an Anfang eines jeden auszugebenden Morse-Tons ausgegeben. Damit kann man den Tongenerator anweissen, nun für ms Millisekunden einen Ton zu erzeugen.

Das zweite Signal wird bei jeden Übergang von Nicht-Ton auf Ton und umgekehrt erzeugt. Man kann es beispielsweise direkt mit einem Objekt verbinden, welches den akt. Zustand anzeigt, z.B einem QLed-Objekt.

symbolChanged() wird für jedes zu sendende Symbol ("-", "." oder " ") aufgerufen.

charChanged() wird für jedes zu sendende Klartext-Zeichen aufgerufen.

Und hasStopped() schließlich wird aufgerufen, wenn der MorseGenerator alle Längeneinheiten in morse abgespielt hat --- und er nicht im Loop-Modus ist.