Inhaltsverzeichnis
Allgemein
In diesem Artikel geht es um die Programmierung des RP6 und seiner Erweiterungsplatinen RP6 CONTROL M32 und RP6 CCPRO M128 am konkreten Beispiel eines Morse-Decoders (Empfänger), eines Morse-Encoders (Sender) und einer Morse-Station (Transceiver).
Zu den Grundlagen des RP6 gibt es eine eigene Seite: RP6. Ebenso zur Programmierung des RP6 im Allgemeinen: RP6 - Programmierung
Geschichte
Nachdem Samuel Morse 1833 den ersten brauchbaren elektromagnetischen Schreibtelegrafen gebaut hatte, fand der erste Testbetrieb 1837 statt. Der verwendete Code umfasste damals nur die zehn Ziffern; die übertragenen Zahlen mussten mit Hilfe einer Tabelle in Buchstaben und Wörter übersetzt werden. Alfred Lewis Vail, ein Mitarbeiter Morses, entwickelte ab 1838 den ersten Code, der auch Buchstaben umfasste. Er bestand aus Zeichen von drei verschiedenen Längen und unterschiedlich langen Pausen. Dieser Code wurde ab 1844 betrieblich eingesetzt (als Morse Landline Code oder American Morse Code bei amerikanischen Eisenbahnen und den Telegrafenunternehmen bis in die 1960er Jahre). Die unterschiedlich langen Pausen stellten eine Unzulänglichkeit des Codes dar, so dass Friedrich Clemens Gerke ihn 1848 zur Inbetriebnahme der elektromagnetischen Telegrafenverbindung zwischen Hamburg und Cuxhaven umschrieb. Dieser Code wurde nach einigen weiteren kleinen Änderungen 1865 auf dem Internationalen Telegraphenkongress in Paris standardisiert und später mit der Einführung der drahtlosen Telegrafie als Internationaler Morsecode von der Internationalen Fernmeldeunion (ITU) genormt. Im Mai 2004 wurde der Morse Code ein zweites Mal anläßlich des 160-jährigen Bestehens der ITU ergänzt, in dem das @ (. - - . - .) offiziell hinzugefügt wurde. Die erste Änderung war ca. 1960 mit der Unterscheidung zwischen Klammer-auf (- . - - .) und Klammer-zu (- . - - . -) erfolgt. Der Morse Code hat in den letzten 10 Jahren immer mehr an Bedeutung verloren. Im Amateurfunk und zu Unterrichtszwecken wird er jedoch noch eingesetzt, auch weiterhin als (Buchstaben-) Kennung von Funknavigationsanlagen (Leuchttürme, Funkfeuer, Radarantwortbaken ...) und bei der Steuerung von Computern durch Menschen mit körperlichen Behinderungen. (Quelle: Wikipedia)
Grundlagen
Der Morse-Code verwendet drei Symbole, die Punkt (.), Strich (-) und Pause ( ) genannt werden.
- Ein Strich (Dah) ist dreimal so lang wie ein Punkt (Dit).
- Die Pause zwischen 2 Symbolen ist ein Dit lang.
- Zwischen den Buchstaben eines Worts gilt eine Pause von einer Dah-Länge (= 3 Dits).
- Die Pause zwischen Wörtern beträgt 7 Dits.
Die Übertragungsrate beim Morsen wird in Buchstaben pro Minute (BpM) oder in Wörtern pro Minute (WpM) gemessen, wobei ein Wort 5 Buchstaben entspricht. Als Referenz für die Geschwindigkeitsmessung wurde das Wort „PARIS“ ausgewählt. Gibt ein Funker dieses Wort mit seinen 5 Buchstaben 12-mal pro Minute, so beträgt die Morse-Geschwindigkeit 60 BpM. Das Wort „PARIS“ besteht aus 50 Dits (d.h. Punkt- plus Strich- plus Pausenlängen). Ein WpM sind 50 Dits pro Minute.
WpM | BpM | Punktlänge [ms] | Strichlänge [ms] |
1 | 5 | 1200 | 3600 |
5 | 25 | 240 | 720 |
10 | 50 | 120 | 360 |
20 | 100 | 60 | 180 |
50 | 250 | 24 | 72 |
100 | 500 | 12 | 36 |
150 | 750 | 8 | 24 |
Anfänger leisten bis zu 5 WpM, die Prüfgeschwindigkeit für Funkamateure liegt bei 12 WpM. Sehr gute Funker schaffen 50 WpM. Weltrekorde: Mehr als 75 WpM!
Morse-Alphabet
Das hier aufgeführte Morse-Alphabet umfasst die englischen Buchstaben und die nicht-englischen Ergänzungen zum Morse-Alphabet. Darüber hinaus gibt es Morse-Codes in vielen Sprachen, die nicht lateinische Buchstaben verwenden: Griechisch, Kyrillisch, Hebräisch, Arabisch, Persisch, Japanisch, Chinesisch, Koreanisch …
Morse-Baum
Mit den "Morse-Bäumen" kann man den Morse-Code lernen oder sehr langsam gesendete Morse-Zeichen direkt decodieren. Im Morse-Baum steht ein Kreis für einen Punkt und ein Rechteck mit abgerundeten Kanten für einen Strich. Beginnt das empfangene Morse-Zeichen mit einem Punkt, folgt man im Morse-Baum "E" den Pfeilen abhängig von den folgenden Punkten/Strichen bis zum Ende des Zeichens. Dort kann man dann das decodierte Zeichen ablesen. Genauso verfährt man im Morse-Baum "T" mit Morse-Zeichen, die mit einem Strich beginnen.
Projekt
Das Empfangen und Senden von Morse-Zeichen ist für einen uC (Microcontroller) eigentlich kein Problem. Die drei Plattformen (Base, M32, M128) des RP6-Systems haben den Vorteil, dass sie aus drei unabhängigen uCs bestehen, die man zum Testen einer Datenübertragung gut benutzen kann. Dazu brauchen die M32 und M128 nur auf dem RP6 montiert zu sein. Als Verbindungen, über die die Morse-Zeichen gesendet werden, kann man die I/O-Pins benutzen, durch die die drei uCs über den XBUS schon verbunden sind (SCL, SDA, EINT1).
Natürlich kann man auch eine "echte" drahtgebundene Morse-Verbindung erreichen, indem man eine der Zusatzplatinen stand-alone betreibt und durch ein Kabel z.B. mit der Base verbindet.
Am reizvollsten ist aber eine Funkverbindung: Der HF-Sender wird z.B. mit einem Ton moduliert, wenn der Ausgangs-Pin des steuernden uCs Highpegel führt. Im HF-Empfänger wird der Eingangs-Pin des decodierenden uCs immer dann auf High-Pegel gezogen, wenn der aufmodulierte Ton empfangen wird. Das ist mit dem RP6-System und etwas Zusatz-Hardware auch für einen Nicht-Funkamateur relativ einfach machbar. Auch die im Radio z.T. noch empfangbaren Morse-Zeichen lassen sich mit einem uC decodieren. Dazu braucht man ebenfalls eine kleine Zusatz-Schaltung.
Planung
Auf allen drei Plattformen (Base, M32, M128) soll ein Morse-Sender und -Empfänger realisiert werden. Beide Funktionen sollen auch parallel nutzbar sein. Auf der RP6 Base und M32 sollen die Funktionen im üblichen Task-System der RP6 Library umgesetzt werden, damit gleichzeitig auch noch weitere Aufgaben ausgeführt werden können. Auf der CCPRO M128 soll der Morse-Sender und -Empfänger in einer 1ms-Interruptroutine parallel zum Hauptprogramm ablaufen.
Auf der M32 und M128 werden die als Morse-Code empfangenen Zeichen auf dem LC-Display dargestellt, auf der Base am Terminal. Als Morse-Code zu sendende Zeichen können an allen Plattformen am Terminal als Text eingegeben werden. Denkbar ist auch, Morse-Zeichen direkt, z.B. mit einer Morse-Taste oder alternativ sogar mit den Bumpern des RP6 einzugeben, sie zu decodieren und anzuzeigen. Viele Möglichkeiten ...
Speicherung der Morse-Zeichen
Auf einem uC ist der Speicherplatz begrenzt, daher ist es wichtig, die Morse-Zeichen möglichst kompakt zu speichern. Da sie sich im Programmablauf nicht ändern, kann man sie auch im EEPROM oder Flash-Speicher ablegen. Ich habe mich für die letzte Option entschieden.
Wie kann man die Dits (Punkte) und Dahs (Striche) am besten speichern? Das längste Morse-Zeichen ...---... (SOS) hat 9 Dits/Dahs. Es ist auch das einzige so lange Zeichen,- alle anderen kommen mit 8 Dits/Dahs hin. Wenn ich SOS nicht berücksichtige, könnte ich die Morse-Zeichen in einem Byte so speichern, dass z.B. ein 0-Bit einem Dit und ein 1-Bit einem Dah entspricht. Das Problem dieser Lösung ist, dass man nicht erkennen kann, wo ein Morse-Zeichen zuende ist. Man müßte also mit mindestens 3 weiteren Bits die Länge des Morse-Zeichens festhalten. Dann bin ich bei einem Platzbedarf pro Morse-Zeichen von 11 Bit,- bei voller Speicherung auch der Ausnahme SOS bei 13 Bit.
Überschaubarer ist es, wenn ich eine 16-Bit Konstante für jedes Morse-Zeichen verwende. Daher lege ich mich auf folgendes Verfahren fest: Ich verwende jeweils 2 Bits für jedes Dit/Dah. Dabei steht die Bitfolge "01" für ein Dit und "11" für ein Dah. Die Bitfolge "00" wird als Ende des Morse-Zeichens gedeutet. Damit kann ich alle Morse-Zeichen einfach speichern,- allerdings nun wieder ohne SOS. Das ist aber kein Problem, weil das nicht existierende Morse-Zeichen ...---.. (SOI) anstelle von SOS gespeichert werden kann. Der Encoder oder Decoder erkennt dies und macht daraus dann wieder SOS.
Beispiel: Der Buchstabe "B" sieht als Morse-Zeichen so -... (Dah-Dit-Dit-Dit) aus. Als 16-Bit Konstante würde ich das "B" dann binär als 0b0000000001010111 speichern. Das entspricht der Hexadezimalzahl 0x0057 oder dezimal 87.
Ein weiteres Beispiel: Das Ausrufezeichen (!) sieht als (nicht ITU-konformes) Morse-Zeichen so -.-.-- (Dah-Dit-Dah-Dit-Dah-Dah) aus. Als 16-Bit Konstante würde ich das "!" dann binär als 0b0000111101110111 speichern. Das entspricht der Hexadezimalzahl 0x0F77 oder dezimal 3959.
Zusätzlich zu dieser Liste der Morse-Zeichen brauche ich für den Morse-Sender noch eine weitere Liste der ASCII-Zeichen mit ihrer Zuordnung zu den Morse-Zeichen. Für Signale wird optional eine weitere Liste benötigt.
Decodierung der Morse-Zeichen
--BAUSTELLE--BAUSTELLE--BAUSTELLE--BAUSTELLE--BAUSTELLE--BAUSTELLE--BAUSTELLE--BAUSTELLE--BAUSTELLE--
Encodierung der Morse-Zeichen
Libraries
RP6 Base
Header
/* **************************************************************************** * _______________________ * \| RP6 ROBOT SYSTEM |/ * \_-_-_-_-_-_-_-_-_-_/ >>> BASE CONTROLLER * ---------------------------------------------------------------------------- * ------------------------ [c]2012 - Dirk ------------------------------------ * **************************************************************************** * File: RP6BaseMorseLib.h * Version: 3.3w * Target: RP6 Base - ATMEGA32 @8.00MHz * Author(s): Dirk * **************************************************************************** * Description: * This is the RP6BaseMorse library header file. * You have to include this file, if you want to use the library * RP6BaseMorseLib.c in your own projects. * * **************************************************************************** * THE CHANGELOG CAN BE FOUND AT THE END OF THIS FILE! * **************************************************************************** */ #ifndef RP6BASEMORSE_H #define RP6BASEMORSE_H /*****************************************************************************/ // Includes: #include "RP6RobotBaseLib.h" // The RP6 Robot Base Library. // Always needs to be included! /*****************************************************************************/ // Defines: #define SPEED 100 // = 12 WpM = 60 CpM // Calculate SPEED: SPEED = 1200 / WpM // SPEED = 6000 / CpM #define SPEED_MIN 400 // = 3 WpM = 15 CpM #define SPEED_MAX 8 // = 150 WpM = 750 CpM #define SPEED_VAR 5 // Decoder speed variation #define LIMITED_PAUSE // Decoder: Spaces limited #define SPACE_CNT_LIMIT 3 // Max. number of spaces //#define DEBUG // Decoder debug mode #define LINE_LENGTH 32 // Terminal line length #define LIGHT // Use LED1 to show Morse sign #define MS_SIGNALS_MAXINDEX 7 #define MS_SPECIALS_MAXINDEX 25 #define MORSESIGNS_MAXINDEX 79 // Flash constants (Morse tables): const uint16_t ms_ft[MORSESIGNS_MAXINDEX + 1]; const uint8_t ms_a0uc_ft[MORSESIGNS_MAXINDEX + 1]; const uint8_t ms_a1uc_ft[MORSESIGNS_MAXINDEX + 1]; const uint8_t ms_a2uc_ft[MORSESIGNS_MAXINDEX + 1]; const uint8_t a_ms_ft[256]; #define MORSEDEC_BUFFER_MAXINDEX 31 // Morse decoder buffer length #define MORSEENC_BUFFER_MAXINDEX 31 // Morse encoder buffer length // Morse decoder/encoder status: #define MORSE_BUFFER_OK 0 #define MORSE_BUFFER_OVERFLOW 1 // Morse buffer overflow /*****************************************************************************/ // Variables: extern uint8_t morsedec_status; extern uint8_t morseenc_status; extern uint8_t morse_error; char morsedec_buffer[MORSEDEC_BUFFER_MAXINDEX + 2]; uint8_t dec_write_pos, dec_read_pos; char morseenc_buffer[MORSEENC_BUFFER_MAXINDEX + 2]; uint8_t enc_write_pos, enc_read_pos; uint16_t decspeed; uint8_t speedvar; uint16_t encspeed; #ifdef DEBUG uint16_t ditlength, dahlength; #endif /*****************************************************************************/ // Functions: uint8_t Lower2UpperCase(uint8_t); uint8_t Upper2LowerCase(uint8_t); uint16_t MsIndex2MorseCode(uint8_t); uint8_t MorseCode2MsIndex(uint16_t); void MorseCode2MsName(char *, uint16_t); uint8_t MsName2MsIndex(char *); void MorseCode2MorseSign(char *, uint16_t); uint16_t MorseSign2MorseCode(char *); void clearMorseDecBuffer(void); void initMorseDecoder(void); void storeMsChar2DecBuffer(uint8_t); void task_MorseDec(void); uint8_t readMorseChar(void); uint8_t readMorseChars(char *, uint8_t); uint8_t getMorseDecBufferLength(void); void initMorseEncoder(void); uint8_t fetchMsIndexFromEncBuffer(void); void task_MorseEnc(void); void storeMsIndex2EncBuffer(uint8_t); void pauseMorse(uint8_t); void writeMorseChar(uint8_t); void writeMorseString(char *); uint8_t getMorseEncBufferLength(void); #ifndef DEBUG void writeMorse(void); #else void writeDebugInfo(void); #endif #endif /****************************************************************************** * Additional info * **************************************************************************** * Changelog: * * ---> changes are documented in the file "RP6BaseMorseLib.c" * * **************************************************************************** */ /*****************************************************************************/ // EOF
Library
/* **************************************************************************** * _______________________ * \| RP6 ROBOT SYSTEM |/ * \_-_-_-_-_-_-_-_-_-_/ >>> BASE CONTROLLER * ---------------------------------------------------------------------------- * ------------------------ [c]2012 - Dirk ------------------------------------ * **************************************************************************** * File: RP6BaseMorseLib.c * Version: 3.3w * Target: RP6 Base - ATMEGA32 @8.00MHz * Author(s): Dirk * **************************************************************************** * Description: * * The RP6 Base Morse Library. * * **************************************************************************** * ATTENTION: The 100us timer is used for the Morse decoder and encoder * task! Please do not alter the variable "timer" elsewhere in * your program! * * **************************************************************************** * THE CHANGELOG CAN BE FOUND AT THE END OF THIS FILE! * **************************************************************************** */ /*****************************************************************************/ // Includes: #include "RP6BaseMorseLib.h" /*****************************************************************************/ // Defines: // RP6 Base Morse Decoder Connection (input): #define MORSEDEC_PORT PORTC #define MORSEDEC_DDR DDRC #define MORSEDEC_PIN PINC //#define MORSEDEC_IN SCL // PINC0 XBUS Pin 10 #define MORSEDEC_IN SDA // PINC1 XBUS Pin 12 //#define MORSEDEC_PORT PORTA //#define MORSEDEC_DDR DDRA //#define MORSEDEC_PIN PINA //#define MORSEDEC_IN E_INT1 // PINA4 XBUS Pin 8 // RP6 Base Morse Encoder Connection (output): //#define MORSEENC_PORT PORTC //#define MORSEENC_DDR DDRC //#define MORSEENC_PIN PINC //#define MORSEENC_IN SCL // PINC0 XBUS Pin 10 //#define MORSEENC_IN SDA // PINC1 XBUS Pin 12 #define MORSEENC_PORT PORTA #define MORSEENC_DDR DDRA #define MORSEENC_PIN PINA #define MORSEENC_IN E_INT1 // PINA4 XBUS Pin 8 // ---------------------------------------------------------------------------- // MORSE TABLES: // Morse Table [0..79]: // Morse decoders and encoders use this table for receiving or sending Morse // code. This table consists of 16-bit constants. Each table index [0..79] // (or each word constant) represents one Morse sign. // The dots (dit) and the dashes (dah) are stored as two bits: The bits "01" // stand for a dit and "11" for a dah, read from right to left in the binary // notation. Between dits and dahs of a Morse sign you have to send a pause // with the length of one dit. Between Morse signs there is a pause with the // length of three dits (or one dah). // // Example: End <<<<7<<6<<5<<4<<3<<2<<1<<<< Start // ---DahDitDitDahDitDitDit // 0x35D5 = 0b0011010111010101 -> 0b 00 11 01 01 11 01 01 01 -> $ (Dollar) const uint16_t ms_ft[] PROGMEM = // Signals (prosigns): // Hex Binary Sign Index Prosign {0x5555, // 0b0101010101010101 0 HH 0x0DD5, // 0b0000110111010101 SK 0x0377, // 0b0000001101110111 CT 0x3757, // 0b0011011101010111 BK 0x5D77, // 0b0101110101110111 CL 0xDF77, // 0b1101111101110111 5 CQ 0x0FD7, // 0b0000111111010111 DO 0x5FD5, // 0b0101111111010101 7 SOS //------------------------------------------------------ // Special characters: // Hex Binary Sign Index Prosign 0x01DF, // 0b0000000111011111 ^G 8 0x00FF, // 0b0000000011111111 CH,^H 0x01FD, // 0b0000000111111101 ^J 10 0x15D5, // 0b0001010111010101 /S 0x01D5, // 0b0000000111010101 ^S VE 0x075F, // 0b0000011101011111 /Z 0x035F, // 0b0000001101011111 .Z 0x037D, // 0b0000001101111101 /A,°A 15 0x00DD, // 0b0000000011011101 Ä AA 0x0177, // 0b0000000101110111 C~ 0x035D, // 0b0000001101011101 \E 0x0175, // 0b0000000101110101 /E 0x01F5, // 0b0000000111110101 Eth 20 0x03DF, // 0b0000001111011111 ~N 0x007F, // 0b0000000001111111 Ö 0x00F5, // 0b0000000011110101 Ü 0x017D, // 0b0000000101111101 Thorn 0x17D5, // 0b0001011111010101 ß 25 //------------------------------------------------------ // Normal characters: // Hex Binary Sign Index Prosign 0x0F77, // 0b0000111101110111 ! 26 0x075D, // 0b0000011101011101 " 0x35D5, // 0b0011010111010101 $ 0x015D, // 0b0000000101011101 & AS 0x07FD, // 0b0000011111111101 ' 30 0x01F7, // 0b0000000111110111 ( KN 0x0DF7, // 0b0000110111110111 ) 0x01DD, // 0b0000000111011101 + AR 0x0F5F, // 0b0000111101011111 , 0x0D57, // 0b0000110101010111 - 35 0x0DDD, // 0b0000110111011101 . 0x01D7, // 0b0000000111010111 / NR 0x03FF, // 0b0000001111111111 0 0x03FD, // 0b0000001111111101 1 0x03F5, // 0b0000001111110101 2 40 0x03D5, // 0b0000001111010101 3 0x0355, // 0b0000001101010101 4 0x0155, // 0b0000000101010101 5 0x0157, // 0b0000000101010111 6 0x015F, // 0b0000000101011111 7 45 0x017F, // 0b0000000101111111 8 0x01FF, // 0b0000000111111111 9 0x057F, // 0b0000010101111111 : 0x0777, // 0b0000011101110111 ; 0x0357, // 0b0000001101010111 = 50 BT 0x05F5, // 0b0000010111110101 ? IMI 0x077D, // 0b0000011101111101 @ 0x000D, // 0b0000000000001101 A 0x0057, // 0b0000000001010111 B DE 0x0077, // 0b0000000001110111 C 55 0x0017, // 0b0000000000010111 D 0x0001, // 0b0000000000000001 E 0x0075, // 0b0000000001110101 F 0x001F, // 0b0000000000011111 G 0x0055, // 0b0000000001010101 H 60 0x0005, // 0b0000000000000101 I 0x00FD, // 0b0000000011111101 J 0x0037, // 0b0000000000110111 K K 0x005D, // 0b0000000001011101 L 0x000F, // 0b0000000000001111 M 65 0x0007, // 0b0000000000000111 N 0x003F, // 0b0000000000111111 O 0x007D, // 0b0000000001111101 P 0x00DF, // 0b0000000011011111 Q 0x001D, // 0b0000000000011101 R 70 R 0x0015, // 0b0000000000010101 S 0x0003, // 0b0000000000000011 T 0x0035, // 0b0000000000110101 U 0x00D5, // 0b0000000011010101 V 0x003D, // 0b0000000000111101 W 75 0x00D7, // 0b0000000011010111 X 0x00F7, // 0b0000000011110111 Y 0x005F, // 0b0000000001011111 Z 0x0DF5};// 0b0000110111110101 _ 79 // Remarks: - SOS (Morse sign ...---...) can not be stored in a 16-bit // constant because SOS is the only Morse sign with 9 dits/dahs. // So SOS is stored as the (not existing) Morse sign ...---.. // (SOI) and must be treated special in decoders/encoders. // Morse-ASCII-Table [0..79]: // Morse decoders use this table for receiving Morse code. const uint8_t ms_a0uc_ft[] PROGMEM = //H S C B C C D S {104,115, 99, 98, 99, 99,100,115, //0 5 //^ C ^ % ^ % * /A Ä C~ \E /E Et ~N Ö Ü To ß 94, 99, 94, 37, 94, 37, 42,193,196,199,200,201,208,209,214,220,222,223, // 10 15 20 25 //! " $ & ' ( ) + , - . / 0 1 2 3 4 5 6 7 8 9 : ; 33,34,36,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59, // 30 35 40 45 //= ? @ A B C D E F G H I J K L M N O P Q 61,63,64,65,66,67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, //50 55 60 65 // R S T U V W X Y Z _ 82, 83, 84, 85, 86, 87, 88, 89, 90,95}; // Et = Eth, To = Thorn //70 75 79 const uint8_t ms_a1uc_ft[] PROGMEM = //H K T K L Q O O {104,107,116,107,108,113,111,111, //0 5 //G H J S S Z Z 103,104,106,115,115,122,122, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 10 15 20 25 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, // 30 35 40 45 32,32,32,32,32,32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //50 55 60 65 32, 32, 32, 32, 32, 32, 32, 32, 32,32}; // Et = Eth, To = Thorn //70 75 79 const uint8_t ms_a2uc_ft[] PROGMEM = // S { 32, 32, 32, 32, 32, 32, 32,115, // 0 5 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 10 15 20 25 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, // 30 35 40 45 32,32,32,32,32,32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //50 55 60 65 32, 32, 32, 32, 32, 32, 32, 32, 32,32}; // Et = Eth, To = Thorn //70 75 79 // Prosigns and special characters are stored as lower case letters (hh, // sk, ^g, ch ...) in this table. // Remarks: - The special chars ^G, ^J, /S, ^S, /Z, .Z [indices 8, 10..14] // are represented as ^g, ^j, %s, ^s, %z, *z in this table. // - If Morse decoders receive a pause with the length of 7 dits, // they have to give out the ASCII code ' ' (space [32]). // ASCII-Morse-Table [0..255]: // Morse encoders use this table to send Morse code. const uint8_t a_ms_ft[] PROGMEM = {51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51, //0 5 10 15 20 51,51,51,51,51,51,51,51, //24 30 //_ ! " ? $ ? & ' ( ) X + , - . / 0 1 2 3 4 5 6 7 79,26,27,51,28,51,29,30,31,32,76,33,34,35,36,37,38,39,40,41,42,43,44,45, //32 35 40 45 50 55 //8 9 : ; ? = ? ? @ A B C D E F G H I J K L M N O 46,47,48,49,51,50,51,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67, //56 60 65 70 75 //P Q R S T U V W X Y Z [ ? ] ? _ ? A B C D E F G 68,69,70,71,72,73,74,75,76,77,78,31,51,32,51,79,51,53,54,55,56,57,58,59, //80 85 90 95 100 //H I J K L M N O P Q R S T U V W X Y Z { ? } ? ? 60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,31,51,32,51,51, //104 110 115 120 125 //? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51, //128 130 135 140 145 150 //? ? ? ? ? ? ? ? _ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 51,51,51,51,51,51,51,51,79,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51, //152 155 160 165 170 175 //? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /A ? ? Ä ? ? C~ 51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,15,51,51,16,51,51,17, //176 180 185 190 195 //\E/E ? ? ? ? ? ? Et ~N ? ? ? ? Ö X ? ? ? ? Ü ? To ß 18,19,51,51,51,51,51,51,20,21,51,51,51,51,22,76,51,51,51,51,23,51,24,25, //200 205 210 215 220 //? /A ? ? Ä ? ? C~ \E /E ? ? ? ? ? ? Et ~N ? ? ? ? Ö / 51,15,51,51,16,51,51,17,18,19,51,51,51,51,51,51,20,21,51,51,51,51,22,37, //224 230 235 240 245 //? ? ? ? Ü ? To ? 51,51,51,51,23,51,24,51}; // Et = Eth, To = Thorn //248 255 // Remarks: - ASCII codes 91 '[' and 123 '{' are converted to Morse // code '(' [31]. // - ASCII codes 93 ']' and 125 '}' are converted to Morse // code ')' [32]. // - ASCII code 215 (multiplication sign) is converted to // Morse code 'X' [76]. // - ASCII code 247 (division sign) is converted to Morse // code '/' [37]. // - ASCII codes 32 (sp) and 160 (nbsp) are represented as // '_' [79] in this table but must be treated special in // encoders: The Morse encoder has to send a pause with // the length of 7 dits for a space. // - All non printable ASCII codes [0..31] and other codes // not defined in the Morse code are converted to Morse // code '?' [51]. // MORSE TABLES (END) // ---------------------------------------------------------------------------- /*****************************************************************************/ // Variables: uint8_t morsedec_status; uint8_t morseenc_status; uint8_t morse_error; /*****************************************************************************/ // Functions: /** * Convert lower case to upper case letters * * Input: ASCII code [0..255] * Output: ASCII code, only with upper case letters * */ uint8_t Lower2UpperCase(uint8_t ch) {uint8_t chuc; chuc = ch; if ((ch >= 97) && (ch <= 122)) { chuc -= 32; } if ((ch >= 224) && (ch <= 254) && (ch != 247)) { chuc -= 32; } return (chuc); } /** * Convert upper case to lower case letters * * Input: ASCII code [0..255] * Output: ASCII code, only with lower case letters * */ uint8_t Upper2LowerCase(uint8_t ch) {uint8_t chlc; chlc = ch; if ((ch >= 65) && (ch <= 90)) { chlc += 32; } if ((ch >= 192) && (ch <= 222) && (ch != 215)) { chlc += 32; } return (chlc); } /** * Output the Morse code of a Morse table index * * Input: Morse table index [0..MORSESIGNS_MAXINDEX] * Output: Morse code (See table ms_ft[] above!) * */ uint16_t MsIndex2MorseCode(uint8_t msindex) { morse_error = false; return (pgm_read_word(&ms_ft[msindex])); } /** * Output the table index of a Morse code * * Input: Morse code (See table ms_ft[] above!) * Output: Morse table index [0..MORSESIGNS_MAXINDEX] * */ uint8_t MorseCode2MsIndex(uint16_t morsecode) {uint8_t msidx; for (msidx = 0; msidx <= MORSESIGNS_MAXINDEX; msidx++) { if (morsecode == pgm_read_word(&ms_ft[msidx])) {break;} } if (msidx <= MORSESIGNS_MAXINDEX) { morse_error = false; return (msidx); // Morse table index } else { morse_error = true; // Unknown Morse code: return (51); // Return table index of '?' } } /** * Output the Morse sign name of a Morse code * * Input: Morse code (See table ms_ft[] above!) * Output: String with Morse sign name (1..3 ASCII letters) * */ void MorseCode2MsName(char *msname, uint16_t morsecode) {uint8_t msidx; msidx = MorseCode2MsIndex(morsecode); msname[0] = pgm_read_byte(&ms_a0uc_ft[msidx]); msname[1] = pgm_read_byte(&ms_a1uc_ft[msidx]); if (msname[1] == 32) {msname[1] = '\0';} msname[2] = pgm_read_byte(&ms_a2uc_ft[msidx]); if (msname[2] == 32) { msname[2] = '\0'; } else { msname[3] = '\0'; } } /** * Output the Morse table index of a Morse sign name * * Input: String with Morse sign name (1..3 ASCII letters) * Output: Morse table index [0..MORSESIGNS_MAXINDEX] * */ uint8_t MsName2MsIndex(char *msname) {uint8_t msidx; for (msidx = 0; msidx <= MORSESIGNS_MAXINDEX; msidx++) { if (msname[0] == pgm_read_byte(&ms_a0uc_ft[msidx])) { if ((pgm_read_byte(&ms_a1uc_ft[msidx]) == 32) || (msname[1] == pgm_read_byte(&ms_a1uc_ft[msidx]))) { if ((pgm_read_byte(&ms_a2uc_ft[msidx]) == 32) || (msname[2] == pgm_read_byte(&ms_a2uc_ft[msidx]))) { break; } } } } if (msidx <= MORSESIGNS_MAXINDEX) { morse_error = false; return (msidx); // Morse table index } else { morse_error = true; // Unknown Morse sign name: return (51); // Return table index of '?' } } /** * Output the Morse sign of a Morse code * * Input: Morse code (See table ms_ft[] above!) * Output: String with the Morse sign (1..9 dits [.] or dahs [-]) * * Example: $ -> 0b0011010111010101 -> Morse sign ...-..- * */ void MorseCode2MorseSign(char *morsesign, uint16_t morsecode) {uint8_t i; uint16_t ms_code; ms_code = morsecode; i = 0; do { switch (ms_code & 3) { case 1 : // dit! morsesign[i] = '.'; i++; break; case 3 : // dah! morsesign[i] = '-'; i++; } ms_code >>= 2; } while (ms_code); if (morsecode == 0x5FD5) { // SOS: Add last dit! morsesign[i] = '.'; i++; } morsesign[i] = '\0'; morse_error = false; } /** * Output the Morse code of a Morse sign * * Input: String with the Morse sign (1..9 dits [.] or dahs [-]) * Output: Morse code (See table ms_ft[] above!) * * Example: $ -> Morse sign ...-..- -> 0b0011010111010101 * */ uint16_t MorseSign2MorseCode(char *morsesign) {uint8_t i, ch; uint16_t ms_code; ms_code = 0; ch = 1; for (i = 0; i <= 7; i++) { ms_code >>= 2; if (ch) { ch = morsesign[i]; switch (ch) { case '.' : // dit! ms_code |= 0x4000; break; case '-' : // dah! ms_code |= 0xC000; } } } if ((ms_code == 0x5FD5) && (morsesign[8] != '.')) { ms_code = 0x05F5; // SOS: If last dit doesn't exist, return '?'! morse_error = true; } else { morse_error = false; } return (ms_code); } /*****************************************************************************/ // Morse decoder functions: /** * Clear the Morse decoder ring buffer * */ void clearMorseDecBuffer(void) { morsedec_status = MORSE_BUFFER_OK; // Decoder buffer status ok dec_write_pos = 255; // Reset buffer write position dec_read_pos = 255; // Reset buffer read position } /** * Init Morse Decoder * * Call this once before using the Morse decoder (receiver) task! * */ void initMorseDecoder(void) { MORSEDEC_DDR &= ~MORSEDEC_IN; // Decoder input pin MORSEDEC_PORT |= MORSEDEC_IN; // MORSEDEC_IN -> Pullup morse_error = false; // Reset Morse error flag clearMorseDecBuffer(); // Clear the decoder buffer decspeed = SPEED; // Decoder speed speedvar = SPEED_VAR; // Decoder speed variation } /** * Store a decoded (prosign) Morse sign char into the decoder ring buffer * * Input: ASCII char (part of a string with the (pro)sign name) * */ void storeMsChar2DecBuffer(uint8_t ch) { if (getMorseDecBufferLength() < MORSEDEC_BUFFER_MAXINDEX) { dec_write_pos++; if (dec_write_pos > MORSEDEC_BUFFER_MAXINDEX) { dec_write_pos = 0; } morsedec_buffer[dec_write_pos] = ch; morsedec_status = MORSE_BUFFER_OK; // Decoder buffer status ok } else { morsedec_status = MORSE_BUFFER_OVERFLOW;// Decoder buffer overflow } } /** * Morse decoder task * */ void task_MorseDec(void) {uint16_t time_100usecs; static char ms_sign[10]; uint8_t temp; static uint16_t last_timer, signal, pause; static uint8_t ditdah, ditdah_cnt; char ms_name[4]; #ifdef LIMITED_PAUSE static uint8_t space_cnt; #endif time_100usecs = timer - last_timer; last_timer += time_100usecs; temp = MORSEDEC_PIN & MORSEDEC_IN; // Read Morse level if (temp) { // Signal on #ifdef LIGHT statusLEDs.LED1 = true; updateStatusLEDs(); #endif signal += time_100usecs; if (pause > (decspeed * 20)) { // Pause > 2 dits: if (ditdah) { // Morse sign end (length 3 dits) ms_sign[ditdah_cnt] = ditdah; ditdah_cnt++; ms_sign[ditdah_cnt] = '\0'; ditdah_cnt = 0; ditdah = 0; MorseCode2MsName(ms_name, MorseSign2MorseCode(ms_sign)); temp = 0; while (ms_name[temp]) { storeMsChar2DecBuffer(ms_name[temp++]); } } pause = 0; } if (pause) { // Short pause: if (ditdah) { // Dit or dah end (length 1 dit) ms_sign[ditdah_cnt] = ditdah; ditdah_cnt++; ms_sign[ditdah_cnt] = '\0'; if (ditdah_cnt > 8) {ditdah_cnt = 0;} ditdah = 0; } pause = 0; } } else { // Signal off (pause) #ifdef LIGHT statusLEDs.LED1 = false; updateStatusLEDs(); #endif pause += time_100usecs; if (pause > (decspeed * 50)) { // Pause > 5 dits: if (ditdah) { // Space or longer pause ms_sign[ditdah_cnt] = ditdah; ditdah_cnt++; ms_sign[ditdah_cnt] = '\0'; ditdah_cnt = 0; ditdah = 0; MorseCode2MsName(ms_name, MorseSign2MorseCode(ms_sign)); temp = 0; while (ms_name[temp]) { storeMsChar2DecBuffer(ms_name[temp++]); } #ifdef LIMITED_PAUSE space_cnt = SPACE_CNT_LIMIT; space_cnt--; #endif storeMsChar2DecBuffer(' '); // Add a space after a sign pause = 0; } #ifdef LIMITED_PAUSE if (space_cnt) { #endif if (pause >= (decspeed * 70)) {// Pause >= 7 dits: storeMsChar2DecBuffer(' '); // Add spaces while pause pause -= (decspeed * 70); #ifdef LIMITED_PAUSE space_cnt--; #endif } #ifdef LIMITED_PAUSE } else { pause = 0; } #endif } if (signal > (decspeed * 20)) { // Signal > 2 dits: #ifdef DEBUG dahlength = signal; #endif ditdah = '-'; // Dah (length 3 dits)! if (signal >= (decspeed * 33)) {// Signal >= 3.3 dits (+10%): decspeed += speedvar; // Reduce decoder speed if (decspeed > SPEED_MIN) {decspeed = SPEED_MIN;} } signal = 0; } if (signal) { // Short signal: #ifdef DEBUG ditlength = signal; #endif ditdah = '.'; // Dit! if (signal <= (decspeed * 9)) {// Signal <= 0.9 dits (-10%): decspeed -= speedvar; // Increase decoder speed if (decspeed < SPEED_MAX) {decspeed = SPEED_MAX;} } signal = 0; } } } /** * Read next character from the Morse decoder ring buffer * * Output: Printable ASCII character [32..255] (as part of * a received/decoded (prosign) Morse sign name) * OR 0 (false), if the ring buffer is empty * */ uint8_t readMorseChar(void) {uint8_t ch; if (dec_read_pos != dec_write_pos) { dec_read_pos++; if (dec_read_pos > MORSEDEC_BUFFER_MAXINDEX) { dec_read_pos = 0; } ch = morsedec_buffer[dec_read_pos]; } else { ch = 0; } return (ch); } /** * Read next [numberOfChars] characters from the Morse decoder ring buffer * * Output: Number of characters copied to *buf, * string *buf with the copied characters * */ uint8_t readMorseChars(char *buf, uint8_t numberOfChars) {uint8_t ch, i; i = 0; while (i < numberOfChars) { ch = readMorseChar(); if (ch) { buf[i] = ch; } else {break;} i++; } buf[i] = '\0'; return (i); } /** * Get the number of characters still in the Morse decoder ring buffer * * Output: Number of characters (0: Buffer is empty!) * */ uint8_t getMorseDecBufferLength(void) {int16_t dec_posdiff; dec_posdiff = dec_write_pos - dec_read_pos; if (dec_posdiff < 0) { dec_posdiff += (MORSEDEC_BUFFER_MAXINDEX + 1); } return ((uint8_t) dec_posdiff); } /*****************************************************************************/ // Morse encoder functions: /** * Init Morse Encoder * * Call this once before using the Morse encoder (sender) task! * */ void initMorseEncoder(void) { MORSEENC_DDR |= MORSEENC_IN; // Encoder output pin MORSEENC_PORT &= ~MORSEENC_IN; // Output low morse_error = false; // Reset Morse error flag morseenc_status = MORSE_BUFFER_OK; // Encoder buffer status ok enc_write_pos = 255; // Reset buffer write pointer enc_read_pos = 255; // Reset buffer read pointer encspeed = SPEED; // Set encoder speed } /** * Fetch next Morse table index from the Morse encoder ring buffer * * Output: Morse table index [0..MORSESIGNS_MAXINDEX(..127)] * OR pause length [129..255] (pause 1..127 dits) * OR 128 (0x80), if the ring buffer is empty * */ uint8_t fetchMsIndexFromEncBuffer(void) {uint8_t msidx; if (enc_read_pos != enc_write_pos) { enc_read_pos++; if (enc_read_pos > MORSEENC_BUFFER_MAXINDEX) { enc_read_pos = 0; } msidx = morseenc_buffer[enc_read_pos]; } else { msidx = 0x80; } return (msidx); } /** * Morse encoder task * */ void task_MorseEnc(void) {static uint8_t busy_flag, signal_flag, pause_flag, sos_flag, pause_dits; static uint16_t last_timer, ms_code; uint8_t msidx; if (busy_flag) { // Encoder busy! if (signal_flag) { // Sending signal if (!pause_flag) { // Waiting for signal end if ((timer - last_timer) >= (encspeed * 10 * (ms_code & 3))) { #ifdef LIGHT statusLEDs.LED1 = false; updateStatusLEDs(); #endif MORSEENC_PORT &= ~MORSEENC_IN; last_timer = timer; pause_flag = true; ms_code >>= 2; } } else { // Pause after a signal if (ms_code) { // Dit/dah (signal) end: if ((timer - last_timer) >= (encspeed * 10)) { signal_flag = false;// Pause 1 dit } } else { // Morse sign end: if (sos_flag) { // Case SOS: ms_code = 0x0001; // Add last dit sos_flag = false; } else { // Case sign end: if ((timer - last_timer) >= (encspeed * 30)) { busy_flag = false;// Pause 3 dits } } } } } else { // Signal end if (pause_dits) { // Make a longer pause if ((timer - last_timer) >= (encspeed * 10 * pause_dits)) { busy_flag = false; // Longer pause end } } else { // Start new signal (dit/dah) #ifdef LIGHT statusLEDs.LED1 = true; updateStatusLEDs(); #endif MORSEENC_PORT |= MORSEENC_IN; last_timer = timer; pause_flag = false; signal_flag = true; } } } else { // Encoder not busy! msidx = fetchMsIndexFromEncBuffer();// Get next index to send if (msidx == 0x80) { // from the ring buffer return; // Buffer empty: Return } else { if (msidx < 0x80) { // Morse sign to send ms_code = MsIndex2MorseCode(msidx); if (ms_code == 0x5FD5) { sos_flag = true; // Sign is SOS } else { sos_flag = false; } pause_dits = 0; } else { // (msidx > 0x80): Longer pause last_timer = timer; pause_dits = msidx - 0x80; } signal_flag = false; busy_flag = true; // Sign / longer pause can be sent } } } /** * Store a Morse table index into the Morse encoder ring buffer * * Input: Morse table index [0..MORSESIGNS_MAXINDEX(..127)] * OR pause length [129..255] (pause 1..127 dits) * */ void storeMsIndex2EncBuffer(uint8_t msindex) { if (getMorseEncBufferLength() < MORSEENC_BUFFER_MAXINDEX) { enc_write_pos++; if (enc_write_pos > MORSEENC_BUFFER_MAXINDEX) { enc_write_pos = 0; } morseenc_buffer[enc_write_pos] = msindex; morseenc_status = MORSE_BUFFER_OK; // Encoder buffer status ok } else { morseenc_status = MORSE_BUFFER_OVERFLOW; // Encoder buffer overflow } } /** * Write a pause length to send into the Morse encoder ring buffer * * Input: Pause length [1..127 dits] (0.14..18.14 spaces) * * With this function you can reach longer pauses. * Examples: * pauseMorse(7); is identical with writeMorseChar(' '); * pauseMorse(14); is identical with writeMorseString(" "); * The function pauseMorse(len) only writes one byte into the encoder ring * buffer for a longer pause, while writeMorseChar(' ') writes one byte for * each space to send. You should use writeMorseChar(' ') for single spaces * (between words) and pauseMorse(len) for longer pauses. * * ATTENTION: !-----------------------------------------------------------! * ! The max. pause length you can reach with this function is ! * ! about 6 seconds! So the max. input value of this function ! * ! depends on encspeed!!! ! * !-----------------------------------------------------------! * ! ==> Max. pause length [dits] = 6000 / encspeed <== ! * !-----------------------------------------------------------! * For encspeeds from 8 (SPEED_MAX) to 47 the max. pause length * is 127 dits. For encspeeds from 48 to 400 (SPEED_MIN) you * calculate the max. number of dits with the above formula. * At SPEED_MIN you may only pause for 15 (6000 / 400) dits! * */ void pauseMorse(uint8_t len) { if (len) { storeMsIndex2EncBuffer(len | 0x80); } } /** * Write a character to send into the Morse encoder ring buffer * * Input: ASCII code [0..255] * */ void writeMorseChar(uint8_t ch) {static uint8_t sign_flag, chidx; uint8_t msidx; static char last_3ch[4]; switch (ch) { case 32 : // Space [ASCII code 32] case 160 : // NbSpace [ASCII code 160] if (sign_flag) { // Space directly after a sign pauseMorse(4); // (length 4 dits) if (morseenc_status == MORSE_BUFFER_OK) { sign_flag = false; } } else { // Pause for all other spaces pauseMorse(7); // (length 7 dits) } break; default : last_3ch[chidx] = ch; last_3ch[chidx + 1] = '\0'; msidx = MsName2MsIndex(last_3ch);// Name in Morse table? if (morse_error) { chidx++; if (chidx > 2) {chidx = 0;} return; } storeMsIndex2EncBuffer(msidx); if (morseenc_status == MORSE_BUFFER_OK) { sign_flag = true; } } chidx = 0; } /** * Write a string to send into the Morse encoder ring buffer * * Input: String with ASCII text * */ void writeMorseString(char *str) { while (*str) { writeMorseChar(*str++); } } /** * Get the number of indices still in the Morse encoder ring buffer * * Output: Number of indices (0: Buffer is empty!) * */ uint8_t getMorseEncBufferLength(void) {int16_t enc_posdiff; enc_posdiff = enc_write_pos - enc_read_pos; if (enc_posdiff < 0) { enc_posdiff += (MORSEENC_BUFFER_MAXINDEX + 1); } return ((uint8_t) enc_posdiff); } /*****************************************************************************/ // Useful UART functions: #ifndef DEBUG /** * Send received Morse signs to the serial interface as ASCII text * */ void writeMorse(void) {static uint8_t pos; uint8_t ch; ch = readMorseChar(); if (ch) { writeChar(ch); pos++; if (pos >= LINE_LENGTH) { pos = 0; writeChar('\n'); } } } #else /** * Send decoder debug information to the serial interface * * Format: .0000 -0000 S000 D000 A:[X] B000 * * . -> Dit length [0.1ms] * - -> Dah length [0.1ms] * S -> Decoder speed (should be (dit length / 10)!) [ms] * D -> Deviation (decoder speed - (dit length / 10)) [ms] * A -> The last received ASCII char * B -> Decoder buffer length (chars still in the buffer) * */ void writeDebugInfo(void) {uint8_t ch; ch = readMorseChar(); if (ch) { writeString_P("."); writeIntegerLength(ditlength, DEC, 4); writeString_P(" -"); writeIntegerLength(dahlength, DEC, 4); writeString_P(" S"); writeIntegerLength(decspeed, DEC, 3); writeString_P(" D"); writeIntegerLength((decspeed - (ditlength / 10)), DEC, 3); writeString_P(" A:["); writeChar(ch); writeString_P("] B"); writeIntegerLength(getMorseDecBufferLength(), DEC, 3); writeChar('\n'); } } #endif /****************************************************************************** * Additional info * **************************************************************************** * Changelog: * - v. 3.3w 2012 by Dirk * * **************************************************************************** */ /*****************************************************************************/ // EOF
RP6 CONTROL M32
Header
/* **************************************************************************** * _______________________ * \| RP6 ROBOT SYSTEM |/ * \_-_-_-_-_-_-_-_-_-_/ >>> RP6 CONTROL * ---------------------------------------------------------------------------- * ------------------------ [c]2012 - Dirk ------------------------------------ * **************************************************************************** * File: RP6ControlMorseLib.h * Version: 3.4w * Target: RP6 CONTROL - ATMEGA32 @16.00MHz * Author(s): Dirk * **************************************************************************** * Description: * This is the RP6ControlMorse library header file. * You have to include this file, if you want to use the library * RP6ControlMorseLib.c in your own projects. * * **************************************************************************** * THE CHANGELOG CAN BE FOUND AT THE END OF THIS FILE! * **************************************************************************** */ #ifndef RP6CONTROLMORSE_H #define RP6CONTROLMORSE_H /*****************************************************************************/ // Includes: #include "RP6ControlLib.h" // The RP6 Control Library. // Always needs to be included! /*****************************************************************************/ // Defines: #define SPEED 100 // = 12 WpM = 60 CpM // Calculate SPEED: SPEED = 1200 / WpM // SPEED = 6000 / CpM #define SPEED_MIN 400 // = 3 WpM = 15 CpM #define SPEED_MAX 8 // = 150 WpM = 750 CpM #define SPEED_VAR 5 // Decoder speed variation #define LIMITED_PAUSE // Decoder: Spaces limited #define SPACE_CNT_LIMIT 3 // Max. number of spaces //#define DEBUG // Decoder debug mode #define LIGHT // Use LED1 to show Morse sign //#define SOUND // Make Morse sign audible #define Tone_D1 149 // 294Hz #define Tone_Dis1 155 // 311Hz #define Tone_E1 160 // 330Hz #define Tone_F1 166 // 349Hz #define Tone_Fis1 171 // 370Hz #define Tone_G1 175 // 392Hz #define Tone_Gis1 180 // 415Hz #define Tone_A1 184 // 440Hz #define Tone_Ais1 188 // 466Hz #define Tone_H1 192 // 494Hz #define Tone_C2 195 // 523Hz #define Tone_Cis2 199 // 554Hz #define Tone_D2 202 // 587Hz #define Tone_Dis2 205 // 622Hz #define Tone_E2 208 // 659Hz #define Tone_F2 210 // 698Hz #define Tone_Fis2 213 // 740Hz #define Tone_G2 215 // 784Hz #define Tone_Gis2 217 // 831Hz #define Tone_A2 219 // 880Hz #define Tone_Ais2 221 // 932Hz #define Tone_H2 223 // 988Hz #define Tone_Off 0 #define MS_SIGNALS_MAXINDEX 7 #define MS_SPECIALS_MAXINDEX 25 #define MORSESIGNS_MAXINDEX 79 // Flash constants (Morse tables): const uint16_t ms_ft[MORSESIGNS_MAXINDEX + 1]; const uint8_t ms_a0uc_ft[MORSESIGNS_MAXINDEX + 1]; const uint8_t ms_a1uc_ft[MORSESIGNS_MAXINDEX + 1]; const uint8_t ms_a2uc_ft[MORSESIGNS_MAXINDEX + 1]; const uint8_t a_ms_ft[256]; #define MORSEDEC_BUFFER_MAXINDEX 31 // Morse decoder buffer length #define MORSEENC_BUFFER_MAXINDEX 31 // Morse encoder buffer length // Morse decoder/encoder status: #define MORSE_BUFFER_OK 0 #define MORSE_BUFFER_OVERFLOW 1 // Morse buffer overflow /*****************************************************************************/ // Variables: extern uint8_t morsedec_status; extern uint8_t morseenc_status; extern uint8_t morse_error; #ifdef SOUND uint8_t tonepitch; #endif char morsedec_buffer[MORSEDEC_BUFFER_MAXINDEX + 2]; uint8_t dec_write_pos, dec_read_pos; char morseenc_buffer[MORSEENC_BUFFER_MAXINDEX + 2]; uint8_t enc_write_pos, enc_read_pos; uint16_t decspeed; uint8_t speedvar; uint16_t encspeed; #ifdef DEBUG uint16_t ditlength, dahlength; #endif /*****************************************************************************/ // Functions: uint8_t Lower2UpperCase(uint8_t); uint8_t Upper2LowerCase(uint8_t); uint16_t MsIndex2MorseCode(uint8_t); uint8_t MorseCode2MsIndex(uint16_t); void MorseCode2MsName(char *, uint16_t); uint8_t MsName2MsIndex(char *); void MorseCode2MorseSign(char *, uint16_t); uint16_t MorseSign2MorseCode(char *); void clearMorseDecBuffer(void); void initMorseDecoder(void); void storeMsChar2DecBuffer(uint8_t); void task_MorseDec(void); uint8_t readMorseChar(void); uint8_t readMorseChars(char *, uint8_t); uint8_t getMorseDecBufferLength(void); void initMorseEncoder(void); uint8_t fetchMsIndexFromEncBuffer(void); void task_MorseEnc(void); void storeMsIndex2EncBuffer(uint8_t); void pauseMorse(uint8_t); void writeMorseChar(uint8_t); void writeMorseString(char *); uint8_t getMorseEncBufferLength(void); #ifndef DEBUG void writeMorseLCD(void); #else void showDebugInfoLCD(void); #endif #endif /****************************************************************************** * Additional info * **************************************************************************** * Changelog: * * ---> changes are documented in the file "RP6ControlMorseLib.c" * * **************************************************************************** */ /*****************************************************************************/ // EOF
Library
/* **************************************************************************** * _______________________ * \| RP6 ROBOT SYSTEM |/ * \_-_-_-_-_-_-_-_-_-_/ >>> RP6 CONTROL * ---------------------------------------------------------------------------- * ------------------------ [c]2012 - Dirk ------------------------------------ * **************************************************************************** * File: RP6ControlMorseLib.c * Version: 3.4w * Target: RP6 CONTROL - ATMEGA32 @16.00MHz * with optional LC-Display 16x2 chars (CONRAD 190911-62) * Author(s): Dirk * **************************************************************************** * Description: * * The RP6 Control Morse Library. * * **************************************************************************** * ATTENTION: The 100us timer is used for the Morse decoder and encoder * task! Please do not alter the variable "timer" elsewhere in * your program! * * **************************************************************************** * THE CHANGELOG CAN BE FOUND AT THE END OF THIS FILE! * **************************************************************************** */ /*****************************************************************************/ // Includes: #include "RP6ControlMorseLib.h" /*****************************************************************************/ // Defines: // RP6 Control Morse Decoder Connection (input): //#define MORSEDEC_PORT PORTC //#define MORSEDEC_DDR DDRC //#define MORSEDEC_PIN PINC //#define MORSEDEC_IN SCL // PINC0 XBUS Pin 10 //#define MORSEDEC_IN SDA // PINC1 XBUS Pin 12 #define MORSEDEC_PORT PORTD #define MORSEDEC_DDR DDRD #define MORSEDEC_PIN PIND #define MORSEDEC_IN EINT1 // PIND2 XBUS Pin 8 // RP6 Control Morse Encoder Connection (output): #define MORSEENC_PORT PORTC #define MORSEENC_DDR DDRC #define MORSEENC_PIN PINC //#define MORSEENC_IN SCL // PINC0 XBUS Pin 10 #define MORSEENC_IN SDA // PINC1 XBUS Pin 12 //#define MORSEENC_PORT PORTD //#define MORSEENC_DDR DDRD //#define MORSEENC_PIN PIND //#define MORSEENC_IN EINT1 // PIND2 XBUS Pin 8 // ---------------------------------------------------------------------------- // MORSE TABLES: // Morse Table [0..79]: // Morse decoders and encoders use this table for receiving or sending Morse // code. This table consists of 16-bit constants. Each table index [0..79] // (or each word constant) represents one Morse sign. // The dots (dit) and the dashes (dah) are stored as two bits: The bits "01" // stand for a dit and "11" for a dah, read from right to left in the binary // notation. Between dits and dahs of a Morse sign you have to send a pause // with the length of one dit. Between Morse signs there is a pause with the // length of three dits (or one dah). // // Example: End <<<<7<<6<<5<<4<<3<<2<<1<<<< Start // ---DahDitDitDahDitDitDit // 0x35D5 = 0b0011010111010101 -> 0b 00 11 01 01 11 01 01 01 -> $ (Dollar) const uint16_t ms_ft[] PROGMEM = // Signals (prosigns): // Hex Binary Sign Index Prosign {0x5555, // 0b0101010101010101 0 HH 0x0DD5, // 0b0000110111010101 SK 0x0377, // 0b0000001101110111 CT 0x3757, // 0b0011011101010111 BK 0x5D77, // 0b0101110101110111 CL 0xDF77, // 0b1101111101110111 5 CQ 0x0FD7, // 0b0000111111010111 DO 0x5FD5, // 0b0101111111010101 7 SOS //------------------------------------------------------ // Special characters: // Hex Binary Sign Index Prosign 0x01DF, // 0b0000000111011111 ^G 8 0x00FF, // 0b0000000011111111 CH,^H 0x01FD, // 0b0000000111111101 ^J 10 0x15D5, // 0b0001010111010101 /S 0x01D5, // 0b0000000111010101 ^S VE 0x075F, // 0b0000011101011111 /Z 0x035F, // 0b0000001101011111 .Z 0x037D, // 0b0000001101111101 /A,°A 15 0x00DD, // 0b0000000011011101 Ä AA 0x0177, // 0b0000000101110111 C~ 0x035D, // 0b0000001101011101 \E 0x0175, // 0b0000000101110101 /E 0x01F5, // 0b0000000111110101 Eth 20 0x03DF, // 0b0000001111011111 ~N 0x007F, // 0b0000000001111111 Ö 0x00F5, // 0b0000000011110101 Ü 0x017D, // 0b0000000101111101 Thorn 0x17D5, // 0b0001011111010101 ß 25 //------------------------------------------------------ // Normal characters: // Hex Binary Sign Index Prosign 0x0F77, // 0b0000111101110111 ! 26 0x075D, // 0b0000011101011101 " 0x35D5, // 0b0011010111010101 $ 0x015D, // 0b0000000101011101 & AS 0x07FD, // 0b0000011111111101 ' 30 0x01F7, // 0b0000000111110111 ( KN 0x0DF7, // 0b0000110111110111 ) 0x01DD, // 0b0000000111011101 + AR 0x0F5F, // 0b0000111101011111 , 0x0D57, // 0b0000110101010111 - 35 0x0DDD, // 0b0000110111011101 . 0x01D7, // 0b0000000111010111 / NR 0x03FF, // 0b0000001111111111 0 0x03FD, // 0b0000001111111101 1 0x03F5, // 0b0000001111110101 2 40 0x03D5, // 0b0000001111010101 3 0x0355, // 0b0000001101010101 4 0x0155, // 0b0000000101010101 5 0x0157, // 0b0000000101010111 6 0x015F, // 0b0000000101011111 7 45 0x017F, // 0b0000000101111111 8 0x01FF, // 0b0000000111111111 9 0x057F, // 0b0000010101111111 : 0x0777, // 0b0000011101110111 ; 0x0357, // 0b0000001101010111 = 50 BT 0x05F5, // 0b0000010111110101 ? IMI 0x077D, // 0b0000011101111101 @ 0x000D, // 0b0000000000001101 A 0x0057, // 0b0000000001010111 B DE 0x0077, // 0b0000000001110111 C 55 0x0017, // 0b0000000000010111 D 0x0001, // 0b0000000000000001 E 0x0075, // 0b0000000001110101 F 0x001F, // 0b0000000000011111 G 0x0055, // 0b0000000001010101 H 60 0x0005, // 0b0000000000000101 I 0x00FD, // 0b0000000011111101 J 0x0037, // 0b0000000000110111 K K 0x005D, // 0b0000000001011101 L 0x000F, // 0b0000000000001111 M 65 0x0007, // 0b0000000000000111 N 0x003F, // 0b0000000000111111 O 0x007D, // 0b0000000001111101 P 0x00DF, // 0b0000000011011111 Q 0x001D, // 0b0000000000011101 R 70 R 0x0015, // 0b0000000000010101 S 0x0003, // 0b0000000000000011 T 0x0035, // 0b0000000000110101 U 0x00D5, // 0b0000000011010101 V 0x003D, // 0b0000000000111101 W 75 0x00D7, // 0b0000000011010111 X 0x00F7, // 0b0000000011110111 Y 0x005F, // 0b0000000001011111 Z 0x0DF5};// 0b0000110111110101 _ 79 // Remarks: - SOS (Morse sign ...---...) can not be stored in a 16-bit // constant because SOS is the only Morse sign with 9 dits/dahs. // So SOS is stored as the (not existing) Morse sign ...---.. // (SOI) and must be treated special in decoders/encoders. // Morse-ASCII-Table [0..79]: // Morse decoders use this table for receiving Morse code. const uint8_t ms_a0uc_ft[] PROGMEM = //H S C B C C D S {104,115, 99, 98, 99, 99,100,115, //0 5 //^ C ^ % ^ % * /A Ä C~ \E /E Et ~N Ö Ü To ß 94, 99, 94, 37, 94, 37, 42,193,196,199,200,201,208,209,214,220,222,223, // 10 15 20 25 //! " $ & ' ( ) + , - . / 0 1 2 3 4 5 6 7 8 9 : ; 33,34,36,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59, // 30 35 40 45 //= ? @ A B C D E F G H I J K L M N O P Q 61,63,64,65,66,67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, //50 55 60 65 // R S T U V W X Y Z _ 82, 83, 84, 85, 86, 87, 88, 89, 90,95}; // Et = Eth, To = Thorn //70 75 79 const uint8_t ms_a1uc_ft[] PROGMEM = //H K T K L Q O O {104,107,116,107,108,113,111,111, //0 5 //G H J S S Z Z 103,104,106,115,115,122,122, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 10 15 20 25 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, // 30 35 40 45 32,32,32,32,32,32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //50 55 60 65 32, 32, 32, 32, 32, 32, 32, 32, 32,32}; // Et = Eth, To = Thorn //70 75 79 const uint8_t ms_a2uc_ft[] PROGMEM = // S { 32, 32, 32, 32, 32, 32, 32,115, // 0 5 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 10 15 20 25 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, // 30 35 40 45 32,32,32,32,32,32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //50 55 60 65 32, 32, 32, 32, 32, 32, 32, 32, 32,32}; // Et = Eth, To = Thorn //70 75 79 // Prosigns and special characters are stored as lower case letters (hh, // sk, ^g, ch ...) in this table. // Remarks: - The special chars ^G, ^J, /S, ^S, /Z, .Z [indices 8, 10..14] // are represented as ^g, ^j, %s, ^s, %z, *z in this table. // - If Morse decoders receive a pause with the length of 7 dits, // they have to give out the ASCII code ' ' (space [32]). // ASCII-Morse-Table [0..255]: // Morse encoders use this table to send Morse code. const uint8_t a_ms_ft[] PROGMEM = {51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51, //0 5 10 15 20 51,51,51,51,51,51,51,51, //24 30 //_ ! " ? $ ? & ' ( ) X + , - . / 0 1 2 3 4 5 6 7 79,26,27,51,28,51,29,30,31,32,76,33,34,35,36,37,38,39,40,41,42,43,44,45, //32 35 40 45 50 55 //8 9 : ; ? = ? ? @ A B C D E F G H I J K L M N O 46,47,48,49,51,50,51,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67, //56 60 65 70 75 //P Q R S T U V W X Y Z [ ? ] ? _ ? A B C D E F G 68,69,70,71,72,73,74,75,76,77,78,31,51,32,51,79,51,53,54,55,56,57,58,59, //80 85 90 95 100 //H I J K L M N O P Q R S T U V W X Y Z { ? } ? ? 60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,31,51,32,51,51, //104 110 115 120 125 //? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51, //128 130 135 140 145 150 //? ? ? ? ? ? ? ? _ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 51,51,51,51,51,51,51,51,79,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51, //152 155 160 165 170 175 //? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /A ? ? Ä ? ? C~ 51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,15,51,51,16,51,51,17, //176 180 185 190 195 //\E/E ? ? ? ? ? ? Et ~N ? ? ? ? Ö X ? ? ? ? Ü ? To ß 18,19,51,51,51,51,51,51,20,21,51,51,51,51,22,76,51,51,51,51,23,51,24,25, //200 205 210 215 220 //? /A ? ? Ä ? ? C~ \E /E ? ? ? ? ? ? Et ~N ? ? ? ? Ö / 51,15,51,51,16,51,51,17,18,19,51,51,51,51,51,51,20,21,51,51,51,51,22,37, //224 230 235 240 245 //? ? ? ? Ü ? To ? 51,51,51,51,23,51,24,51}; // Et = Eth, To = Thorn //248 255 // Remarks: - ASCII codes 91 '[' and 123 '{' are converted to Morse // code '(' [31]. // - ASCII codes 93 ']' and 125 '}' are converted to Morse // code ')' [32]. // - ASCII code 215 (multiplication sign) is converted to // Morse code 'X' [76]. // - ASCII code 247 (division sign) is converted to Morse // code '/' [37]. // - ASCII codes 32 (sp) and 160 (nbsp) are represented as // '_' [79] in this table but must be treated special in // encoders: The Morse encoder has to send a pause with // the length of 7 dits for a space. // - All non printable ASCII codes [0..31] and other codes // not defined in the Morse code are converted to Morse // code '?' [51]. // MORSE TABLES (END) // ---------------------------------------------------------------------------- /*****************************************************************************/ // Variables: uint8_t morsedec_status; uint8_t morseenc_status; uint8_t morse_error; /*****************************************************************************/ // Functions: /** * Convert lower case to upper case letters * * Input: ASCII code [0..255] * Output: ASCII code, only with upper case letters * */ uint8_t Lower2UpperCase(uint8_t ch) {uint8_t chuc; chuc = ch; if ((ch >= 97) && (ch <= 122)) { chuc -= 32; } if ((ch >= 224) && (ch <= 254) && (ch != 247)) { chuc -= 32; } return (chuc); } /** * Convert upper case to lower case letters * * Input: ASCII code [0..255] * Output: ASCII code, only with lower case letters * */ uint8_t Upper2LowerCase(uint8_t ch) {uint8_t chlc; chlc = ch; if ((ch >= 65) && (ch <= 90)) { chlc += 32; } if ((ch >= 192) && (ch <= 222) && (ch != 215)) { chlc += 32; } return (chlc); } /** * Output the Morse code of a Morse table index * * Input: Morse table index [0..MORSESIGNS_MAXINDEX] * Output: Morse code (See table ms_ft[] above!) * */ uint16_t MsIndex2MorseCode(uint8_t msindex) { morse_error = false; return (pgm_read_word(&ms_ft[msindex])); } /** * Output the table index of a Morse code * * Input: Morse code (See table ms_ft[] above!) * Output: Morse table index [0..MORSESIGNS_MAXINDEX] * */ uint8_t MorseCode2MsIndex(uint16_t morsecode) {uint8_t msidx; for (msidx = 0; msidx <= MORSESIGNS_MAXINDEX; msidx++) { if (morsecode == pgm_read_word(&ms_ft[msidx])) {break;} } if (msidx <= MORSESIGNS_MAXINDEX) { morse_error = false; return (msidx); // Morse table index } else { morse_error = true; // Unknown Morse code: return (51); // Return table index of '?' } } /** * Output the Morse sign name of a Morse code * * Input: Morse code (See table ms_ft[] above!) * Output: String with Morse sign name (1..3 ASCII letters) * */ void MorseCode2MsName(char *msname, uint16_t morsecode) {uint8_t msidx; msidx = MorseCode2MsIndex(morsecode); msname[0] = pgm_read_byte(&ms_a0uc_ft[msidx]); msname[1] = pgm_read_byte(&ms_a1uc_ft[msidx]); if (msname[1] == 32) {msname[1] = '\0';} msname[2] = pgm_read_byte(&ms_a2uc_ft[msidx]); if (msname[2] == 32) { msname[2] = '\0'; } else { msname[3] = '\0'; } } /** * Output the Morse table index of a Morse sign name * * Input: String with Morse sign name (1..3 ASCII letters) * Output: Morse table index [0..MORSESIGNS_MAXINDEX] * */ uint8_t MsName2MsIndex(char *msname) {uint8_t msidx; for (msidx = 0; msidx <= MORSESIGNS_MAXINDEX; msidx++) { if (msname[0] == pgm_read_byte(&ms_a0uc_ft[msidx])) { if ((pgm_read_byte(&ms_a1uc_ft[msidx]) == 32) || (msname[1] == pgm_read_byte(&ms_a1uc_ft[msidx]))) { if ((pgm_read_byte(&ms_a2uc_ft[msidx]) == 32) || (msname[2] == pgm_read_byte(&ms_a2uc_ft[msidx]))) { break; } } } } if (msidx <= MORSESIGNS_MAXINDEX) { morse_error = false; return (msidx); // Morse table index } else { morse_error = true; // Unknown Morse sign name: return (51); // Return table index of '?' } } /** * Output the Morse sign of a Morse code * * Input: Morse code (See table ms_ft[] above!) * Output: String with the Morse sign (1..9 dits [.] or dahs [-]) * * Example: $ -> 0b0011010111010101 -> Morse sign ...-..- * */ void MorseCode2MorseSign(char *morsesign, uint16_t morsecode) {uint8_t i; uint16_t ms_code; ms_code = morsecode; i = 0; do { switch (ms_code & 3) { case 1 : // dit! morsesign[i] = '.'; i++; break; case 3 : // dah! morsesign[i] = '-'; i++; } ms_code >>= 2; } while (ms_code); if (morsecode == 0x5FD5) { // SOS: Add last dit! morsesign[i] = '.'; i++; } morsesign[i] = '\0'; morse_error = false; } /** * Output the Morse code of a Morse sign * * Input: String with the Morse sign (1..9 dits [.] or dahs [-]) * Output: Morse code (See table ms_ft[] above!) * * Example: $ -> Morse sign ...-..- -> 0b0011010111010101 * */ uint16_t MorseSign2MorseCode(char *morsesign) {uint8_t i, ch; uint16_t ms_code; ms_code = 0; ch = 1; for (i = 0; i <= 7; i++) { ms_code >>= 2; if (ch) { ch = morsesign[i]; switch (ch) { case '.' : // dit! ms_code |= 0x4000; break; case '-' : // dah! ms_code |= 0xC000; } } } if ((ms_code == 0x5FD5) && (morsesign[8] != '.')) { ms_code = 0x05F5; // SOS: If last dit doesn't exist, return '?'! morse_error = true; } else { morse_error = false; } return (ms_code); } /*****************************************************************************/ // Morse decoder functions: /** * Clear the Morse decoder ring buffer * */ void clearMorseDecBuffer(void) { morsedec_status = MORSE_BUFFER_OK; // Decoder buffer status ok dec_write_pos = 255; // Reset buffer write position dec_read_pos = 255; // Reset buffer read position } /** * Init Morse Decoder * * Call this once before using the Morse decoder (receiver) task! * */ void initMorseDecoder(void) { MORSEDEC_DDR &= ~MORSEDEC_IN; // Decoder input pin MORSEDEC_PORT |= MORSEDEC_IN; // MORSEDEC_IN -> Pullup morse_error = false; // Reset Morse error flag clearMorseDecBuffer(); // Clear the decoder buffer decspeed = SPEED; // Decoder speed speedvar = SPEED_VAR; // Decoder speed variation #ifdef SOUND tonepitch = Tone_C2; // Set tone pitch #endif } /** * Store a decoded (prosign) Morse sign char into the decoder ring buffer * * Input: ASCII char (part of a string with the (pro)sign name) * */ void storeMsChar2DecBuffer(uint8_t ch) { if (getMorseDecBufferLength() < MORSEDEC_BUFFER_MAXINDEX) { dec_write_pos++; if (dec_write_pos > MORSEDEC_BUFFER_MAXINDEX) { dec_write_pos = 0; } morsedec_buffer[dec_write_pos] = ch; morsedec_status = MORSE_BUFFER_OK; // Decoder buffer status ok } else { morsedec_status = MORSE_BUFFER_OVERFLOW;// Decoder buffer overflow } } /** * Morse decoder task * */ void task_MorseDec(void) {uint16_t time_100usecs; static char ms_sign[10]; uint8_t temp; static uint16_t last_timer, signal, pause; static uint8_t ditdah, ditdah_cnt; char ms_name[4]; #ifdef SOUND static uint8_t tone_off; #endif #ifdef LIMITED_PAUSE static uint8_t space_cnt; #endif time_100usecs = timer - last_timer; last_timer += time_100usecs; temp = MORSEDEC_PIN & MORSEDEC_IN; // Read Morse level if (temp) { // Signal on #ifdef SOUND if (tone_off) { setBeeperPitch(tonepitch); tone_off = false; } #endif #ifdef LIGHT externalPort.LED1 = true; outputExt(); #endif signal += time_100usecs; if (pause > (decspeed * 20)) { // Pause > 2 dits: if (ditdah) { // Morse sign end (length 3 dits) ms_sign[ditdah_cnt] = ditdah; ditdah_cnt++; ms_sign[ditdah_cnt] = '\0'; ditdah_cnt = 0; ditdah = 0; MorseCode2MsName(ms_name, MorseSign2MorseCode(ms_sign)); temp = 0; while (ms_name[temp]) { storeMsChar2DecBuffer(ms_name[temp++]); } } pause = 0; } if (pause) { // Short pause: if (ditdah) { // Dit or dah end (length 1 dit) ms_sign[ditdah_cnt] = ditdah; ditdah_cnt++; ms_sign[ditdah_cnt] = '\0'; if (ditdah_cnt > 8) {ditdah_cnt = 0;} ditdah = 0; } pause = 0; } } else { // Signal off (pause) #ifdef SOUND setBeeperPitch(Tone_Off); tone_off = true; #endif #ifdef LIGHT externalPort.LED1 = false; outputExt(); #endif pause += time_100usecs; if (pause > (decspeed * 50)) { // Pause > 5 dits: if (ditdah) { // Space or longer pause ms_sign[ditdah_cnt] = ditdah; ditdah_cnt++; ms_sign[ditdah_cnt] = '\0'; ditdah_cnt = 0; ditdah = 0; MorseCode2MsName(ms_name, MorseSign2MorseCode(ms_sign)); temp = 0; while (ms_name[temp]) { storeMsChar2DecBuffer(ms_name[temp++]); } #ifdef LIMITED_PAUSE space_cnt = SPACE_CNT_LIMIT; space_cnt--; #endif storeMsChar2DecBuffer(' '); // Add a space after a sign pause = 0; } #ifdef LIMITED_PAUSE if (space_cnt) { #endif if (pause >= (decspeed * 70)) {// Pause >= 7 dits: storeMsChar2DecBuffer(' '); // Add spaces while pause pause -= (decspeed * 70); #ifdef LIMITED_PAUSE space_cnt--; #endif } #ifdef LIMITED_PAUSE } else { pause = 0; } #endif } if (signal > (decspeed * 20)) { // Signal > 2 dits: #ifdef DEBUG dahlength = signal; #endif ditdah = '-'; // Dah (length 3 dits)! if (signal >= (decspeed * 33)) {// Signal >= 3.3 dits (+10%): decspeed += speedvar; // Reduce decoder speed if (decspeed > SPEED_MIN) {decspeed = SPEED_MIN;} } signal = 0; } if (signal) { // Short signal: #ifdef DEBUG ditlength = signal; #endif ditdah = '.'; // Dit! if (signal <= (decspeed * 9)) {// Signal <= 0.9 dits (-10%): decspeed -= speedvar; // Increase decoder speed if (decspeed < SPEED_MAX) {decspeed = SPEED_MAX;} } signal = 0; } } } /** * Read next character from the Morse decoder ring buffer * * Output: Printable ASCII character [32..255] (as part of * a received/decoded (prosign) Morse sign name) * OR 0 (false), if the ring buffer is empty * */ uint8_t readMorseChar(void) {uint8_t ch; if (dec_read_pos != dec_write_pos) { dec_read_pos++; if (dec_read_pos > MORSEDEC_BUFFER_MAXINDEX) { dec_read_pos = 0; } ch = morsedec_buffer[dec_read_pos]; } else { ch = 0; } return (ch); } /** * Read next [numberOfChars] characters from the Morse decoder ring buffer * * Output: Number of characters copied to *buf, * string *buf with the copied characters * */ uint8_t readMorseChars(char *buf, uint8_t numberOfChars) {uint8_t ch, i; i = 0; while (i < numberOfChars) { ch = readMorseChar(); if (ch) { buf[i] = ch; } else {break;} i++; } buf[i] = '\0'; return (i); } /** * Get the number of characters still in the Morse decoder ring buffer * * Output: Number of characters (0: Buffer is empty!) * */ uint8_t getMorseDecBufferLength(void) {int16_t dec_posdiff; dec_posdiff = dec_write_pos - dec_read_pos; if (dec_posdiff < 0) { dec_posdiff += (MORSEDEC_BUFFER_MAXINDEX + 1); } return ((uint8_t) dec_posdiff); } /*****************************************************************************/ // Morse encoder functions: /** * Init Morse Encoder * * Call this once before using the Morse encoder (sender) task! * */ void initMorseEncoder(void) { MORSEENC_DDR |= MORSEENC_IN; // Encoder output pin MORSEENC_PORT &= ~MORSEENC_IN; // Output low morse_error = false; // Reset Morse error flag morseenc_status = MORSE_BUFFER_OK; // Encoder buffer status ok enc_write_pos = 255; // Reset buffer write pointer enc_read_pos = 255; // Reset buffer read pointer encspeed = SPEED; // Set encoder speed #ifdef SOUND tonepitch = Tone_C2; // Set tone pitch #endif } /** * Fetch next Morse table index from the Morse encoder ring buffer * * Output: Morse table index [0..MORSESIGNS_MAXINDEX(..127)] * OR pause length [129..255] (pause 1..127 dits) * OR 128 (0x80), if the ring buffer is empty * */ uint8_t fetchMsIndexFromEncBuffer(void) {uint8_t msidx; if (enc_read_pos != enc_write_pos) { enc_read_pos++; if (enc_read_pos > MORSEENC_BUFFER_MAXINDEX) { enc_read_pos = 0; } msidx = morseenc_buffer[enc_read_pos]; } else { msidx = 0x80; } return (msidx); } /** * Morse encoder task * */ void task_MorseEnc(void) {static uint8_t busy_flag, signal_flag, pause_flag, sos_flag, pause_dits; static uint16_t last_timer, ms_code; uint8_t msidx; if (busy_flag) { // Encoder busy! if (signal_flag) { // Sending signal if (!pause_flag) { // Waiting for signal end if ((timer - last_timer) >= (encspeed * 10 * (ms_code & 3))) { #ifdef SOUND setBeeperPitch(Tone_Off); #endif #ifdef LIGHT externalPort.LED1 = false; outputExt(); #endif MORSEENC_PORT &= ~MORSEENC_IN; last_timer = timer; pause_flag = true; ms_code >>= 2; } } else { // Pause after a signal if (ms_code) { // Dit/dah (signal) end: if ((timer - last_timer) >= (encspeed * 10)) { signal_flag = false;// Pause 1 dit } } else { // Morse sign end: if (sos_flag) { // Case SOS: ms_code = 0x0001; // Add last dit sos_flag = false; } else { // Case sign end: if ((timer - last_timer) >= (encspeed * 30)) { busy_flag = false;// Pause 3 dits } } } } } else { // Signal end if (pause_dits) { // Make a longer pause if ((timer - last_timer) >= (encspeed * 10 * pause_dits)) { busy_flag = false; // Longer pause end } } else { // Start new signal (dit/dah) #ifdef SOUND setBeeperPitch(tonepitch); #endif #ifdef LIGHT externalPort.LED1 = true; outputExt(); #endif MORSEENC_PORT |= MORSEENC_IN; last_timer = timer; pause_flag = false; signal_flag = true; } } } else { // Encoder not busy! msidx = fetchMsIndexFromEncBuffer();// Get next index to send if (msidx == 0x80) { // from the ring buffer return; // Buffer empty: Return } else { if (msidx < 0x80) { // Morse sign to send ms_code = MsIndex2MorseCode(msidx); if (ms_code == 0x5FD5) { sos_flag = true; // Sign is SOS } else { sos_flag = false; } pause_dits = 0; } else { // (msidx > 0x80): Longer pause last_timer = timer; pause_dits = msidx - 0x80; } signal_flag = false; busy_flag = true; // Sign / longer pause can be sent } } } /** * Store a Morse table index into the Morse encoder ring buffer * * Input: Morse table index [0..MORSESIGNS_MAXINDEX(..127)] * OR pause length [129..255] (pause 1..127 dits) * */ void storeMsIndex2EncBuffer(uint8_t msindex) { if (getMorseEncBufferLength() < MORSEENC_BUFFER_MAXINDEX) { enc_write_pos++; if (enc_write_pos > MORSEENC_BUFFER_MAXINDEX) { enc_write_pos = 0; } morseenc_buffer[enc_write_pos] = msindex; morseenc_status = MORSE_BUFFER_OK; // Encoder buffer status ok } else { morseenc_status = MORSE_BUFFER_OVERFLOW; // Encoder buffer overflow } } /** * Write a pause length to send into the Morse encoder ring buffer * * Input: Pause length [1..127 dits] (0.14..18.14 spaces) * * With this function you can reach longer pauses. * Examples: * pauseMorse(7); is identical with writeMorseChar(' '); * pauseMorse(14); is identical with writeMorseString(" "); * The function pauseMorse(len) only writes one byte into the encoder ring * buffer for a longer pause, while writeMorseChar(' ') writes one byte for * each space to send. You should use writeMorseChar(' ') for single spaces * (between words) and pauseMorse(len) for longer pauses. * * ATTENTION: !-----------------------------------------------------------! * ! The max. pause length you can reach with this function is ! * ! about 6 seconds! So the max. input value of this function ! * ! depends on encspeed!!! ! * !-----------------------------------------------------------! * ! ==> Max. pause length [dits] = 6000 / encspeed <== ! * !-----------------------------------------------------------! * For encspeeds from 8 (SPEED_MAX) to 47 the max. pause length * is 127 dits. For encspeeds from 48 to 400 (SPEED_MIN) you * calculate the max. number of dits with the above formula. * At SPEED_MIN you may only pause for 15 (6000 / 400) dits! * */ void pauseMorse(uint8_t len) { if (len) { storeMsIndex2EncBuffer(len | 0x80); } } /** * Write a character to send into the Morse encoder ring buffer * * Input: ASCII code [0..255] * */ void writeMorseChar(uint8_t ch) {static uint8_t sign_flag, chidx; uint8_t msidx; static char last_3ch[4]; switch (ch) { case 32 : // Space [ASCII code 32] case 160 : // NbSpace [ASCII code 160] if (sign_flag) { // Space directly after a sign pauseMorse(4); // (length 4 dits) if (morseenc_status == MORSE_BUFFER_OK) { sign_flag = false; } } else { // Pause for all other spaces pauseMorse(7); // (length 7 dits) } break; default : last_3ch[chidx] = ch; last_3ch[chidx + 1] = '\0'; msidx = MsName2MsIndex(last_3ch);// Name in Morse table? if (morse_error) { chidx++; if (chidx > 2) {chidx = 0;} return; } storeMsIndex2EncBuffer(msidx); if (morseenc_status == MORSE_BUFFER_OK) { sign_flag = true; } } chidx = 0; } /** * Write a string to send into the Morse encoder ring buffer * * Input: String with ASCII text * */ void writeMorseString(char *str) { while (*str) { writeMorseChar(*str++); } } /** * Get the number of indices still in the Morse encoder ring buffer * * Output: Number of indices (0: Buffer is empty!) * */ uint8_t getMorseEncBufferLength(void) {int16_t enc_posdiff; enc_posdiff = enc_write_pos - enc_read_pos; if (enc_posdiff < 0) { enc_posdiff += (MORSEENC_BUFFER_MAXINDEX + 1); } return ((uint8_t) enc_posdiff); } /*****************************************************************************/ // Useful LCD functions: #ifndef DEBUG /** * Show received Morse signs on the LCD 16x2 chars as ASCII text * */ void writeMorseLCD(void) {static uint8_t pos; static char line2[17]; uint8_t ch; ch = readMorseChar(); if (ch) { writeCharLCD(ch); line2[pos] = ch; pos++; if (pos >= 16) { pos = 0; clearLCD(); writeStringLCD(line2); // Copy line 2 to line 1 setCursorPosLCD(1, 0); // line 2, pos 1 } } } #else /** * Show decoder debug information on the LCD * * Format: .0000 -0000 S000 * B000 A[XXX] D000 * * . -> Dit length [0.1ms] * - -> Dah length [0.1ms] * S -> Decoder speed (should be (dit length / 10)!) [ms] * B -> Decoder buffer length (chars still in the buffer) * A -> The 3 last received ASCII chars * D -> Deviation (decoder speed - (dit length / 10)) [ms] * */ void showDebugInfoLCD(void) {static char last_3ch[4]; uint8_t ch; ch = readMorseChar(); if (ch) { last_3ch[0] = last_3ch[1]; last_3ch[1] = last_3ch[2]; last_3ch[2] = ch; last_3ch[3] = '\0'; setCursorPosLCD(0, 0); // line 1, pos 1 writeStringLCD_P("."); writeIntegerLengthLCD(ditlength, DEC, 4); writeStringLCD_P(" -"); writeIntegerLengthLCD(dahlength, DEC, 4); writeStringLCD_P(" S"); writeIntegerLengthLCD(decspeed, DEC, 3); setCursorPosLCD(1, 0); // line 2, pos 1 writeStringLCD_P("B"); writeIntegerLengthLCD(getMorseDecBufferLength(), DEC, 3); writeStringLCD_P(" A["); writeStringLCD(last_3ch); writeStringLCD_P("] D"); writeIntegerLengthLCD((decspeed - (ditlength / 10)), DEC, 3); } } #endif /****************************************************************************** * Additional info * **************************************************************************** * Changelog: * - v. 3.4w 2012 by Dirk * * **************************************************************************** */ /*****************************************************************************/ // EOF
RP6 CCPRO M128
...
Demos
RP6 Base
...
RP6 CONTROL M32
...
RP6 CCPRO M128
...
Optionen
Direkteingabe von Morse-Code
Rundfunkempfang von Morse-Code
Morse-Funkstrecke
Weiteres
Erfahrungsberichte, Weiterentwicklung
... kann gerne ergänzt werden ...
Siehe auch
Weblinks
Autoren
--Dirk 20:21, 12. Mär 2012 (CET)