morse.c revision 78793
12490Sjkh/* 22490Sjkh * Copyright (c) 1988, 1993 32490Sjkh * The Regents of the University of California. All rights reserved. 42490Sjkh * 52490Sjkh * Redistribution and use in source and binary forms, with or without 62490Sjkh * modification, are permitted provided that the following conditions 72490Sjkh * are met: 82490Sjkh * 1. Redistributions of source code must retain the above copyright 92490Sjkh * notice, this list of conditions and the following disclaimer. 102490Sjkh * 2. Redistributions in binary form must reproduce the above copyright 112490Sjkh * notice, this list of conditions and the following disclaimer in the 122490Sjkh * documentation and/or other materials provided with the distribution. 132490Sjkh * 3. All advertising materials mentioning features or use of this software 142490Sjkh * must display the following acknowledgement: 152490Sjkh * This product includes software developed by the University of 162490Sjkh * California, Berkeley and its contributors. 172490Sjkh * 4. Neither the name of the University nor the names of its contributors 182490Sjkh * may be used to endorse or promote products derived from this software 192490Sjkh * without specific prior written permission. 202490Sjkh * 212490Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 222490Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 232490Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 242490Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 252490Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 262490Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 272490Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 282490Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 292490Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 302490Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 312490Sjkh * SUCH DAMAGE. 322490Sjkh */ 332490Sjkh 3410352Sjoerg/* 3510352Sjoerg * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM) 3610352Sjoerg * <lyndon@orthanc.com> 3710352Sjoerg */ 3810352Sjoerg 392490Sjkh#ifndef lint 4053920Sbillfstatic const char copyright[] = 412490Sjkh"@(#) Copyright (c) 1988, 1993\n\ 422490Sjkh The Regents of the University of California. All rights reserved.\n"; 432490Sjkh#endif /* not lint */ 442490Sjkh 452490Sjkh#ifndef lint 4653920Sbillf#if 0 472490Sjkhstatic char sccsid[] = "@(#)morse.c 8.1 (Berkeley) 5/31/93"; 4853920Sbillf#endif 4953920Sbillfstatic const char rcsid[] = 5053920Sbillf "$FreeBSD: head/games/morse/morse.c 78793 2001-06-26 01:43:52Z ache $"; 512490Sjkh#endif /* not lint */ 522490Sjkh 5357527Sjoerg#include <sys/time.h> 5457527Sjoerg 552490Sjkh#include <ctype.h> 5657527Sjoerg#include <fcntl.h> 5778793Sache#include <langinfo.h> 5810352Sjoerg#include <locale.h> 5957527Sjoerg#include <signal.h> 6057527Sjoerg#include <stdio.h> 6110352Sjoerg#include <stdlib.h> 6235857Sjb#include <string.h> 6357527Sjoerg#include <termios.h> 6454622Sbillf#include <unistd.h> 652490Sjkh 6610352Sjoerg#ifdef SPEAKER 6710352Sjoerg#include <machine/speaker.h> 6810352Sjoerg#endif 6910352Sjoerg 7010352Sjoergstruct morsetab { 7110352Sjoerg char inchar; 7210352Sjoerg char *morse; 732490Sjkh}; 742490Sjkh 7554622Sbillfstatic const struct morsetab mtab[] = { 762490Sjkh 7710352Sjoerg /* letters */ 7810352Sjoerg 7954622Sbillf {'a', ".-"}, 8054622Sbillf {'b', "-..."}, 8154622Sbillf {'c', "-.-."}, 8254622Sbillf {'d', "-.."}, 8354622Sbillf {'e', "."}, 8454622Sbillf {'f', "..-."}, 8554622Sbillf {'g', "--."}, 8654622Sbillf {'h', "...."}, 8754622Sbillf {'i', ".."}, 8854622Sbillf {'j', ".---"}, 8954622Sbillf {'k', "-.-"}, 9054622Sbillf {'l', ".-.."}, 9154622Sbillf {'m', "--"}, 9254622Sbillf {'n', "-."}, 9354622Sbillf {'o', "---"}, 9454622Sbillf {'p', ".--."}, 9554622Sbillf {'q', "--.-"}, 9654622Sbillf {'r', ".-."}, 9754622Sbillf {'s', "..."}, 9854622Sbillf {'t', "-"}, 9954622Sbillf {'u', "..-"}, 10054622Sbillf {'v', "...-"}, 10154622Sbillf {'w', ".--"}, 10254622Sbillf {'x', "-..-"}, 10354622Sbillf {'y', "-.--"}, 10454622Sbillf {'z', "--.."}, 10510352Sjoerg 10610352Sjoerg /* digits */ 10710352Sjoerg 10854622Sbillf {'0', "-----"}, 10954622Sbillf {'1', ".----"}, 11054622Sbillf {'2', "..---"}, 11154622Sbillf {'3', "...--"}, 11254622Sbillf {'4', "....-"}, 11354622Sbillf {'5', "....."}, 11454622Sbillf {'6', "-...."}, 11554622Sbillf {'7', "--..."}, 11654622Sbillf {'8', "---.."}, 11754622Sbillf {'9', "----."}, 11810352Sjoerg 11910352Sjoerg /* punctuation */ 12010352Sjoerg 12154622Sbillf {',', "--..--"}, 12254622Sbillf {'.', ".-.-.-"}, 12354622Sbillf {'?', "..--.."}, 12454622Sbillf {'/', "-..-."}, 12554622Sbillf {'-', "-....-"}, 12654622Sbillf {'=', "-...-"}, /* BT */ 12754622Sbillf {':', "---..."}, 12854622Sbillf {';', "-.-.-."}, 12954622Sbillf {'(', "-.--."}, /* KN */ 13054622Sbillf {')', "-.--.-"}, 13154622Sbillf {'$', "...-..-"}, 13254622Sbillf {'+', ".-.-."}, /* AR */ 13310352Sjoerg 13410352Sjoerg /* prosigns without already assigned values */ 13510352Sjoerg 13654622Sbillf {'#', ".-..."}, /* AS */ 13754622Sbillf {'@', "...-.-"}, /* SK */ 13854622Sbillf {'*', "...-."}, /* VE */ 13954622Sbillf {'%', "-...-.-"}, /* BK */ 14010352Sjoerg 14154622Sbillf {'\0', ""} 14210352Sjoerg}; 14310352Sjoerg 14410352Sjoerg 14554622Sbillfstatic const struct morsetab iso8859tab[] = { 14654622Sbillf {'�', ".--.-"}, 14754622Sbillf {'�', ".--.-"}, 14854622Sbillf {'�', ".--.-"}, 14954622Sbillf {'�', ".-.-"}, 15054622Sbillf {'�', "-.-.."}, 15154622Sbillf {'�', "..-.."}, 15254622Sbillf {'�', "..-.."}, 15354622Sbillf {'�', "-..-."}, 15454622Sbillf {'�', "---."}, 15554622Sbillf {'�', "..--"}, 15610352Sjoerg 15754622Sbillf {'\0', ""} 15810352Sjoerg}; 15910352Sjoerg 16054622Sbillfstatic const struct morsetab koi8rtab[] = { 16110352Sjoerg /* 16210352Sjoerg * the cyrillic alphabet; you'll need a KOI8R font in order 16310352Sjoerg * to see the actual characters 16410352Sjoerg */ 16554622Sbillf {'�', ".-"}, /* a */ 16654622Sbillf {'�', "-..."}, /* be */ 16754622Sbillf {'�', ".--"}, /* ve */ 16854622Sbillf {'�', "--."}, /* ge */ 16954622Sbillf {'�', "-.."}, /* de */ 17054622Sbillf {'�', "."}, /* ye */ 17154622Sbillf {'�', "."}, /* yo, the same as ye */ 17254622Sbillf {'�', "...-"}, /* she */ 17354622Sbillf {'�', "--.."}, /* ze */ 17454622Sbillf {'�', ".."}, /* i */ 17554622Sbillf {'�', ".---"}, /* i kratkoye */ 17654622Sbillf {'�', "-.-"}, /* ka */ 17754622Sbillf {'�', ".-.."}, /* el */ 17854622Sbillf {'�', "--"}, /* em */ 17954622Sbillf {'�', "-."}, /* en */ 18054622Sbillf {'�', "---"}, /* o */ 18154622Sbillf {'�', ".--."}, /* pe */ 18254622Sbillf {'�', ".-."}, /* er */ 18354622Sbillf {'�', "..."}, /* es */ 18454622Sbillf {'�', "-"}, /* te */ 18554622Sbillf {'�', "..-"}, /* u */ 18654622Sbillf {'�', "..-."}, /* ef */ 18754622Sbillf {'�', "...."}, /* kha */ 18854622Sbillf {'�', "-.-."}, /* ce */ 18954622Sbillf {'�', "---."}, /* che */ 19054622Sbillf {'�', "----"}, /* sha */ 19154622Sbillf {'�', "--.-"}, /* shcha */ 19254622Sbillf {'�', "-.--"}, /* yi */ 19354622Sbillf {'�', "-..-"}, /* myakhkij znak */ 19454622Sbillf {'�', "..-.."}, /* ae */ 19554622Sbillf {'�', "..--"}, /* yu */ 19654622Sbillf {'�', ".-.-"}, /* ya */ 19710352Sjoerg 19854622Sbillf {'\0', ""} 19910352Sjoerg}; 20010352Sjoerg 20110352Sjoergvoid show(const char *), play(const char *), morse(char); 20257527Sjoergvoid ttyout(const char *); 20357527Sjoergvoid sighandler(int); 20410352Sjoerg 20557527Sjoerg#define GETOPTOPTS "d:ef:sw:" 20657527Sjoerg#define USAGE \ 20757527Sjoerg"usage: morse [-s] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n" 20857527Sjoerg 20957527Sjoergstatic int pflag, sflag, eflag; 21010352Sjoergstatic int wpm = 20; /* words per minute */ 21110352Sjoerg#define FREQUENCY 600 21210352Sjoergstatic int freq = FREQUENCY; 21357527Sjoergstatic char *device; /* for tty-controlled generator */ 21410352Sjoerg 21510352Sjoerg#define DASH_LEN 3 21610352Sjoerg#define CHAR_SPACE 3 21710352Sjoerg#define WORD_SPACE (7 - CHAR_SPACE - 1) 21810352Sjoergstatic float dot_clock; 21957527Sjoergint spkr, line; 22057527Sjoergstruct termios otty, ntty; 22157527Sjoergint olflags; 22257527Sjoerg 22357527Sjoerg#ifdef SPEAKER 22410352Sjoergtone_t sound; 22557527Sjoerg#undef GETOPTOPTS 22657527Sjoerg#define GETOPTOPTS "d:ef:psw:" 22757527Sjoerg#undef USAGE 22857527Sjoerg#define USAGE \ 22957527Sjoerg"usage: morse [-s] [-p] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n" 23010352Sjoerg#endif 23110352Sjoerg 23278793Sachestatic const struct morsetab *hightab; 23310352Sjoerg 23410352Sjoergint 23510352Sjoergmain(int argc, char **argv) 2362490Sjkh{ 23757527Sjoerg int ch, lflags; 23878793Sache char *p, *codeset; 2392490Sjkh 24057527Sjoerg while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1) 24110352Sjoerg switch ((char) ch) { 24257527Sjoerg case 'd': 24357527Sjoerg device = optarg; 24457527Sjoerg break; 24557527Sjoerg case 'e': 24657527Sjoerg eflag = 1; 24757527Sjoerg setvbuf(stdout, 0, _IONBF, 0); 24857527Sjoerg break; 24910352Sjoerg case 'f': 25010352Sjoerg freq = atoi(optarg); 25110352Sjoerg break; 25257527Sjoerg#ifdef SPEAKER 25310352Sjoerg case 'p': 25410352Sjoerg pflag = 1; 25510352Sjoerg break; 25657527Sjoerg#endif 2572490Sjkh case 's': 2582490Sjkh sflag = 1; 2592490Sjkh break; 26010352Sjoerg case 'w': 26110352Sjoerg wpm = atoi(optarg); 26210352Sjoerg break; 2632490Sjkh case '?': 2642490Sjkh default: 26557527Sjoerg fputs(USAGE, stderr); 2662490Sjkh exit(1); 2672490Sjkh } 26857527Sjoerg if ((pflag || device) && sflag) { 26957527Sjoerg fputs("morse: only one of -p, -d and -s allowed\n", stderr); 27010352Sjoerg exit(1); 27110352Sjoerg } 27257527Sjoerg if ((pflag || device) && ((wpm < 1) || (wpm > 60))) { 27310352Sjoerg fputs("morse: insane speed\n", stderr); 27410352Sjoerg exit(1); 27510352Sjoerg } 27657527Sjoerg if ((pflag || device) && (freq == 0)) 27710352Sjoerg freq = FREQUENCY; 27810352Sjoerg 27910352Sjoerg#ifdef SPEAKER 28010352Sjoerg if (pflag) { 28110352Sjoerg if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) { 28210352Sjoerg perror(SPEAKER); 28310352Sjoerg exit(1); 28410352Sjoerg } 28557527Sjoerg } else 28657527Sjoerg#endif 28757527Sjoerg if (device) { 28857527Sjoerg if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) { 28957527Sjoerg perror("open tty line"); 29057527Sjoerg exit(1); 29157527Sjoerg } 29257527Sjoerg if (tcgetattr(line, &otty) == -1) { 29357527Sjoerg perror("tcgetattr() failed"); 29457527Sjoerg exit(1); 29557527Sjoerg } 29657527Sjoerg ntty = otty; 29757527Sjoerg ntty.c_cflag |= CLOCAL; 29857527Sjoerg tcsetattr(line, TCSANOW, &ntty); 29957527Sjoerg lflags = fcntl(line, F_GETFL); 30057527Sjoerg lflags &= ~O_NONBLOCK; 30157527Sjoerg fcntl(line, F_SETFL, &lflags); 30257527Sjoerg ioctl(line, TIOCMGET, &lflags); 30357527Sjoerg lflags &= ~TIOCM_RTS; 30457527Sjoerg olflags = lflags; 30557527Sjoerg ioctl(line, TIOCMSET, &lflags); 30657527Sjoerg (void)signal(SIGHUP, sighandler); 30757527Sjoerg (void)signal(SIGINT, sighandler); 30857527Sjoerg (void)signal(SIGQUIT, sighandler); 30957527Sjoerg (void)signal(SIGTERM, sighandler); 31057527Sjoerg } 31157527Sjoerg if (pflag || device) { 31210352Sjoerg dot_clock = wpm / 2.4; /* dots/sec */ 31310352Sjoerg dot_clock = 1 / dot_clock; /* duration of a dot */ 31410352Sjoerg dot_clock = dot_clock / 2; /* dot_clock runs at twice */ 31510352Sjoerg /* the dot rate */ 31610352Sjoerg dot_clock = dot_clock * 100; /* scale for ioctl */ 31710352Sjoerg } 31857527Sjoerg 3192490Sjkh argc -= optind; 3202490Sjkh argv += optind; 3212490Sjkh 32278793Sache if (setlocale(LC_CTYPE, "") != NULL && 32378793Sache *(codeset = nl_langinfo(CODESET)) != '\0') { 32478793Sache if (strcmp(codeset, "KOI8-R") == 0) 32510352Sjoerg hightab = koi8rtab; 32678793Sache else if (strcmp(codeset, "ISO8859-1") == 0 || 32778793Sache strcmp(codeset, "ISO8859-15") == 0) 32878793Sache hightab = iso8859tab; 32910352Sjoerg } 33010352Sjoerg 33110352Sjoerg if (*argv) { 3322490Sjkh do { 33310352Sjoerg for (p = *argv; *p; ++p) { 33457527Sjoerg if (eflag) 33557527Sjoerg putchar(*p); 33629018Sache morse(*p); 33710352Sjoerg } 33857527Sjoerg if (eflag) 33957527Sjoerg putchar(' '); 34029018Sache morse(' '); 3412490Sjkh } while (*++argv); 34210352Sjoerg } else { 34357527Sjoerg while ((ch = getchar()) != EOF) { 34457527Sjoerg if (eflag) 34557527Sjoerg putchar(ch); 34610352Sjoerg morse(ch); 34757527Sjoerg } 34810352Sjoerg } 34957527Sjoerg if (device) 35057527Sjoerg tcsetattr(line, TCSANOW, &otty); 35110352Sjoerg exit(0); 3522490Sjkh} 3532490Sjkh 35410352Sjoergvoid 35510352Sjoergmorse(char c) 3562490Sjkh{ 35754622Sbillf const struct morsetab *m; 35810352Sjoerg 35929018Sache if (isalpha((unsigned char)c)) 36029018Sache c = tolower((unsigned char)c); 36110352Sjoerg if ((c == '\r') || (c == '\n')) 36210352Sjoerg c = ' '; 36310352Sjoerg if (c == ' ') { 36410352Sjoerg if (pflag) { 36510352Sjoerg play(" "); 36610352Sjoerg return; 36757527Sjoerg } else if (device) { 36857527Sjoerg ttyout(" "); 36957527Sjoerg return; 37010352Sjoerg } else { 37110352Sjoerg show(""); 37210352Sjoerg return; 37310352Sjoerg } 37410352Sjoerg } 37510352Sjoerg for (m = ((unsigned char)c < 0x80? mtab: hightab); 37678793Sache m != NULL && m->inchar != '\0'; 37710352Sjoerg m++) { 37810352Sjoerg if (m->inchar == c) { 37910352Sjoerg if (pflag) { 38010352Sjoerg play(m->morse); 38157527Sjoerg } else if (device) { 38257527Sjoerg ttyout(m->morse); 38310352Sjoerg } else 38410352Sjoerg show(m->morse); 38510352Sjoerg } 38610352Sjoerg } 3872490Sjkh} 3882490Sjkh 38910352Sjoergvoid 39010352Sjoergshow(const char *s) 3912490Sjkh{ 3922490Sjkh if (sflag) 3932490Sjkh printf(" %s", s); 39410352Sjoerg else 39510352Sjoerg for (; *s; ++s) 39610352Sjoerg printf(" %s", *s == '.' ? "dit" : "dah"); 39710352Sjoerg printf("\n"); 3982490Sjkh} 39910352Sjoerg 40010352Sjoergvoid 40110352Sjoergplay(const char *s) 40210352Sjoerg{ 40310352Sjoerg#ifdef SPEAKER 40410352Sjoerg const char *c; 40510352Sjoerg 40610352Sjoerg for (c = s; *c != '\0'; c++) { 40729018Sache switch (*c) { 40810352Sjoerg case '.': 40910352Sjoerg sound.frequency = freq; 41010352Sjoerg sound.duration = dot_clock; 41110352Sjoerg break; 41210352Sjoerg case '-': 41310352Sjoerg sound.frequency = freq; 41410352Sjoerg sound.duration = dot_clock * DASH_LEN; 41510352Sjoerg break; 41610352Sjoerg case ' ': 41710352Sjoerg sound.frequency = 0; 41810352Sjoerg sound.duration = dot_clock * WORD_SPACE; 41910352Sjoerg break; 42010352Sjoerg default: 42110352Sjoerg sound.duration = 0; 42210352Sjoerg } 42310352Sjoerg if (sound.duration) { 42410352Sjoerg if (ioctl(spkr, SPKRTONE, &sound) == -1) { 42510352Sjoerg perror("ioctl play"); 42610352Sjoerg exit(1); 42710352Sjoerg } 42810352Sjoerg } 42910352Sjoerg sound.frequency = 0; 43010352Sjoerg sound.duration = dot_clock; 43110352Sjoerg if (ioctl(spkr, SPKRTONE, &sound) == -1) { 43210352Sjoerg perror("ioctl rest"); 43310352Sjoerg exit(1); 43410352Sjoerg } 43510352Sjoerg } 43610352Sjoerg sound.frequency = 0; 43710352Sjoerg sound.duration = dot_clock * CHAR_SPACE; 43810352Sjoerg ioctl(spkr, SPKRTONE, &sound); 43910352Sjoerg#endif 44010352Sjoerg} 44157527Sjoerg 44257527Sjoergvoid 44357527Sjoergttyout(const char *s) 44457527Sjoerg{ 44557527Sjoerg const char *c; 44657527Sjoerg int duration, on, lflags; 44757527Sjoerg 44857527Sjoerg for (c = s; *c != '\0'; c++) { 44957527Sjoerg switch (*c) { 45057527Sjoerg case '.': 45157527Sjoerg on = 1; 45257527Sjoerg duration = dot_clock; 45357527Sjoerg break; 45457527Sjoerg case '-': 45557527Sjoerg on = 1; 45657527Sjoerg duration = dot_clock * DASH_LEN; 45757527Sjoerg break; 45857527Sjoerg case ' ': 45957527Sjoerg on = 0; 46057527Sjoerg duration = dot_clock * WORD_SPACE; 46157527Sjoerg break; 46257527Sjoerg default: 46357527Sjoerg on = 0; 46457527Sjoerg duration = 0; 46557527Sjoerg } 46657527Sjoerg if (on) { 46757527Sjoerg ioctl(line, TIOCMGET, &lflags); 46857527Sjoerg lflags |= TIOCM_RTS; 46957527Sjoerg ioctl(line, TIOCMSET, &lflags); 47057527Sjoerg } 47157527Sjoerg duration *= 10000; 47257527Sjoerg if (duration) 47357527Sjoerg usleep(duration); 47457527Sjoerg ioctl(line, TIOCMGET, &lflags); 47557527Sjoerg lflags &= ~TIOCM_RTS; 47657527Sjoerg ioctl(line, TIOCMSET, &lflags); 47757527Sjoerg duration = dot_clock * 10000; 47857527Sjoerg usleep(duration); 47957527Sjoerg } 48057527Sjoerg duration = dot_clock * CHAR_SPACE * 10000; 48157527Sjoerg usleep(duration); 48257527Sjoerg} 48357527Sjoerg 48457527Sjoergvoid 48557527Sjoergsighandler(int signo) 48657527Sjoerg{ 48757527Sjoerg 48857527Sjoerg ioctl(line, TIOCMSET, &olflags); 48957527Sjoerg tcsetattr(line, TCSANOW, &otty); 49057527Sjoerg 49157527Sjoerg signal(signo, SIG_DFL); 49257527Sjoerg (void)kill(getpid(), signo); 49357527Sjoerg} 494