morse.c revision 57527
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 57527 2000-02-27 01:21:28Z joerg $"; 512490Sjkh#endif /* not lint */ 522490Sjkh 5357527Sjoerg#include <sys/time.h> 5457527Sjoerg 552490Sjkh#include <ctype.h> 5657527Sjoerg#include <fcntl.h> 5710352Sjoerg#include <locale.h> 5857527Sjoerg#include <signal.h> 5957527Sjoerg#include <stdio.h> 6010352Sjoerg#include <stdlib.h> 6135857Sjb#include <string.h> 6257527Sjoerg#include <termios.h> 6354622Sbillf#include <unistd.h> 642490Sjkh 6510352Sjoerg#ifdef SPEAKER 6610352Sjoerg#include <machine/speaker.h> 6710352Sjoerg#endif 6810352Sjoerg 6910352Sjoergstruct morsetab { 7010352Sjoerg char inchar; 7110352Sjoerg char *morse; 722490Sjkh}; 732490Sjkh 7454622Sbillfstatic const struct morsetab mtab[] = { 752490Sjkh 7610352Sjoerg /* letters */ 7710352Sjoerg 7854622Sbillf {'a', ".-"}, 7954622Sbillf {'b', "-..."}, 8054622Sbillf {'c', "-.-."}, 8154622Sbillf {'d', "-.."}, 8254622Sbillf {'e', "."}, 8354622Sbillf {'f', "..-."}, 8454622Sbillf {'g', "--."}, 8554622Sbillf {'h', "...."}, 8654622Sbillf {'i', ".."}, 8754622Sbillf {'j', ".---"}, 8854622Sbillf {'k', "-.-"}, 8954622Sbillf {'l', ".-.."}, 9054622Sbillf {'m', "--"}, 9154622Sbillf {'n', "-."}, 9254622Sbillf {'o', "---"}, 9354622Sbillf {'p', ".--."}, 9454622Sbillf {'q', "--.-"}, 9554622Sbillf {'r', ".-."}, 9654622Sbillf {'s', "..."}, 9754622Sbillf {'t', "-"}, 9854622Sbillf {'u', "..-"}, 9954622Sbillf {'v', "...-"}, 10054622Sbillf {'w', ".--"}, 10154622Sbillf {'x', "-..-"}, 10254622Sbillf {'y', "-.--"}, 10354622Sbillf {'z', "--.."}, 10410352Sjoerg 10510352Sjoerg /* digits */ 10610352Sjoerg 10754622Sbillf {'0', "-----"}, 10854622Sbillf {'1', ".----"}, 10954622Sbillf {'2', "..---"}, 11054622Sbillf {'3', "...--"}, 11154622Sbillf {'4', "....-"}, 11254622Sbillf {'5', "....."}, 11354622Sbillf {'6', "-...."}, 11454622Sbillf {'7', "--..."}, 11554622Sbillf {'8', "---.."}, 11654622Sbillf {'9', "----."}, 11710352Sjoerg 11810352Sjoerg /* punctuation */ 11910352Sjoerg 12054622Sbillf {',', "--..--"}, 12154622Sbillf {'.', ".-.-.-"}, 12254622Sbillf {'?', "..--.."}, 12354622Sbillf {'/', "-..-."}, 12454622Sbillf {'-', "-....-"}, 12554622Sbillf {'=', "-...-"}, /* BT */ 12654622Sbillf {':', "---..."}, 12754622Sbillf {';', "-.-.-."}, 12854622Sbillf {'(', "-.--."}, /* KN */ 12954622Sbillf {')', "-.--.-"}, 13054622Sbillf {'$', "...-..-"}, 13154622Sbillf {'+', ".-.-."}, /* AR */ 13210352Sjoerg 13310352Sjoerg /* prosigns without already assigned values */ 13410352Sjoerg 13554622Sbillf {'#', ".-..."}, /* AS */ 13654622Sbillf {'@', "...-.-"}, /* SK */ 13754622Sbillf {'*', "...-."}, /* VE */ 13854622Sbillf {'%', "-...-.-"}, /* BK */ 13910352Sjoerg 14054622Sbillf {'\0', ""} 14110352Sjoerg}; 14210352Sjoerg 14310352Sjoerg 14454622Sbillfstatic const struct morsetab iso8859tab[] = { 14554622Sbillf {'�', ".--.-"}, 14654622Sbillf {'�', ".--.-"}, 14754622Sbillf {'�', ".--.-"}, 14854622Sbillf {'�', ".-.-"}, 14954622Sbillf {'�', "-.-.."}, 15054622Sbillf {'�', "..-.."}, 15154622Sbillf {'�', "..-.."}, 15254622Sbillf {'�', "-..-."}, 15354622Sbillf {'�', "---."}, 15454622Sbillf {'�', "..--"}, 15510352Sjoerg 15654622Sbillf {'\0', ""} 15710352Sjoerg}; 15810352Sjoerg 15954622Sbillfstatic const struct morsetab koi8rtab[] = { 16010352Sjoerg /* 16110352Sjoerg * the cyrillic alphabet; you'll need a KOI8R font in order 16210352Sjoerg * to see the actual characters 16310352Sjoerg */ 16454622Sbillf {'�', ".-"}, /* a */ 16554622Sbillf {'�', "-..."}, /* be */ 16654622Sbillf {'�', ".--"}, /* ve */ 16754622Sbillf {'�', "--."}, /* ge */ 16854622Sbillf {'�', "-.."}, /* de */ 16954622Sbillf {'�', "."}, /* ye */ 17054622Sbillf {'�', "."}, /* yo, the same as ye */ 17154622Sbillf {'�', "...-"}, /* she */ 17254622Sbillf {'�', "--.."}, /* ze */ 17354622Sbillf {'�', ".."}, /* i */ 17454622Sbillf {'�', ".---"}, /* i kratkoye */ 17554622Sbillf {'�', "-.-"}, /* ka */ 17654622Sbillf {'�', ".-.."}, /* el */ 17754622Sbillf {'�', "--"}, /* em */ 17854622Sbillf {'�', "-."}, /* en */ 17954622Sbillf {'�', "---"}, /* o */ 18054622Sbillf {'�', ".--."}, /* pe */ 18154622Sbillf {'�', ".-."}, /* er */ 18254622Sbillf {'�', "..."}, /* es */ 18354622Sbillf {'�', "-"}, /* te */ 18454622Sbillf {'�', "..-"}, /* u */ 18554622Sbillf {'�', "..-."}, /* ef */ 18654622Sbillf {'�', "...."}, /* kha */ 18754622Sbillf {'�', "-.-."}, /* ce */ 18854622Sbillf {'�', "---."}, /* che */ 18954622Sbillf {'�', "----"}, /* sha */ 19054622Sbillf {'�', "--.-"}, /* shcha */ 19154622Sbillf {'�', "-.--"}, /* yi */ 19254622Sbillf {'�', "-..-"}, /* myakhkij znak */ 19354622Sbillf {'�', "..-.."}, /* ae */ 19454622Sbillf {'�', "..--"}, /* yu */ 19554622Sbillf {'�', ".-.-"}, /* ya */ 19610352Sjoerg 19754622Sbillf {'\0', ""} 19810352Sjoerg}; 19910352Sjoerg 20010352Sjoergvoid show(const char *), play(const char *), morse(char); 20157527Sjoergvoid ttyout(const char *); 20257527Sjoergvoid sighandler(int); 20310352Sjoerg 20457527Sjoerg#define GETOPTOPTS "d:ef:sw:" 20557527Sjoerg#define USAGE \ 20657527Sjoerg"usage: morse [-s] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n" 20757527Sjoerg 20857527Sjoergstatic int pflag, sflag, eflag; 20910352Sjoergstatic int wpm = 20; /* words per minute */ 21010352Sjoerg#define FREQUENCY 600 21110352Sjoergstatic int freq = FREQUENCY; 21257527Sjoergstatic char *device; /* for tty-controlled generator */ 21310352Sjoerg 21410352Sjoerg#define DASH_LEN 3 21510352Sjoerg#define CHAR_SPACE 3 21610352Sjoerg#define WORD_SPACE (7 - CHAR_SPACE - 1) 21710352Sjoergstatic float dot_clock; 21857527Sjoergint spkr, line; 21957527Sjoergstruct termios otty, ntty; 22057527Sjoergint olflags; 22157527Sjoerg 22257527Sjoerg#ifdef SPEAKER 22310352Sjoergtone_t sound; 22457527Sjoerg#undef GETOPTOPTS 22557527Sjoerg#define GETOPTOPTS "d:ef:psw:" 22657527Sjoerg#undef USAGE 22757527Sjoerg#define USAGE \ 22857527Sjoerg"usage: morse [-s] [-p] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n" 22910352Sjoerg#endif 23010352Sjoerg 23154622Sbillfstatic const struct morsetab *hightab = iso8859tab; 23210352Sjoerg 23310352Sjoergint 23410352Sjoergmain(int argc, char **argv) 2352490Sjkh{ 23657527Sjoerg int ch, lflags; 23753210Sbillf char *p; 2382490Sjkh 23957527Sjoerg while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1) 24010352Sjoerg switch ((char) ch) { 24157527Sjoerg case 'd': 24257527Sjoerg device = optarg; 24357527Sjoerg break; 24457527Sjoerg case 'e': 24557527Sjoerg eflag = 1; 24657527Sjoerg setvbuf(stdout, 0, _IONBF, 0); 24757527Sjoerg break; 24810352Sjoerg case 'f': 24910352Sjoerg freq = atoi(optarg); 25010352Sjoerg break; 25157527Sjoerg#ifdef SPEAKER 25210352Sjoerg case 'p': 25310352Sjoerg pflag = 1; 25410352Sjoerg break; 25557527Sjoerg#endif 2562490Sjkh case 's': 2572490Sjkh sflag = 1; 2582490Sjkh break; 25910352Sjoerg case 'w': 26010352Sjoerg wpm = atoi(optarg); 26110352Sjoerg break; 2622490Sjkh case '?': 2632490Sjkh default: 26457527Sjoerg fputs(USAGE, stderr); 2652490Sjkh exit(1); 2662490Sjkh } 26757527Sjoerg if ((pflag || device) && sflag) { 26857527Sjoerg fputs("morse: only one of -p, -d and -s allowed\n", stderr); 26910352Sjoerg exit(1); 27010352Sjoerg } 27157527Sjoerg if ((pflag || device) && ((wpm < 1) || (wpm > 60))) { 27210352Sjoerg fputs("morse: insane speed\n", stderr); 27310352Sjoerg exit(1); 27410352Sjoerg } 27557527Sjoerg if ((pflag || device) && (freq == 0)) 27610352Sjoerg freq = FREQUENCY; 27710352Sjoerg 27810352Sjoerg#ifdef SPEAKER 27910352Sjoerg if (pflag) { 28010352Sjoerg if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) { 28110352Sjoerg perror(SPEAKER); 28210352Sjoerg exit(1); 28310352Sjoerg } 28457527Sjoerg } else 28557527Sjoerg#endif 28657527Sjoerg if (device) { 28757527Sjoerg if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) { 28857527Sjoerg perror("open tty line"); 28957527Sjoerg exit(1); 29057527Sjoerg } 29157527Sjoerg if (tcgetattr(line, &otty) == -1) { 29257527Sjoerg perror("tcgetattr() failed"); 29357527Sjoerg exit(1); 29457527Sjoerg } 29557527Sjoerg ntty = otty; 29657527Sjoerg ntty.c_cflag |= CLOCAL; 29757527Sjoerg tcsetattr(line, TCSANOW, &ntty); 29857527Sjoerg lflags = fcntl(line, F_GETFL); 29957527Sjoerg lflags &= ~O_NONBLOCK; 30057527Sjoerg fcntl(line, F_SETFL, &lflags); 30157527Sjoerg ioctl(line, TIOCMGET, &lflags); 30257527Sjoerg lflags &= ~TIOCM_RTS; 30357527Sjoerg olflags = lflags; 30457527Sjoerg ioctl(line, TIOCMSET, &lflags); 30557527Sjoerg (void)signal(SIGHUP, sighandler); 30657527Sjoerg (void)signal(SIGINT, sighandler); 30757527Sjoerg (void)signal(SIGQUIT, sighandler); 30857527Sjoerg (void)signal(SIGTERM, sighandler); 30957527Sjoerg } 31057527Sjoerg if (pflag || device) { 31110352Sjoerg dot_clock = wpm / 2.4; /* dots/sec */ 31210352Sjoerg dot_clock = 1 / dot_clock; /* duration of a dot */ 31310352Sjoerg dot_clock = dot_clock / 2; /* dot_clock runs at twice */ 31410352Sjoerg /* the dot rate */ 31510352Sjoerg dot_clock = dot_clock * 100; /* scale for ioctl */ 31610352Sjoerg } 31757527Sjoerg 3182490Sjkh argc -= optind; 3192490Sjkh argv += optind; 3202490Sjkh 32129018Sache if((p = getenv("LC_CTYPE")) || 32229018Sache (p = getenv("LC_ALL")) || 32329018Sache (p = getenv("LANG"))) { 32429018Sache if(strlen(p) >= sizeof(".KOI8-R") && 32529018Sache strcasecmp(&p[strlen(p) + 1 - sizeof(".KOI8-R")], ".KOI8-R") == 0) 32610352Sjoerg hightab = koi8rtab; 32710352Sjoerg } 32829018Sache (void) setlocale(LC_CTYPE, ""); 32910352Sjoerg 33010352Sjoerg if (*argv) { 3312490Sjkh do { 33210352Sjoerg for (p = *argv; *p; ++p) { 33357527Sjoerg if (eflag) 33457527Sjoerg putchar(*p); 33529018Sache morse(*p); 33610352Sjoerg } 33757527Sjoerg if (eflag) 33857527Sjoerg putchar(' '); 33929018Sache morse(' '); 3402490Sjkh } while (*++argv); 34110352Sjoerg } else { 34257527Sjoerg while ((ch = getchar()) != EOF) { 34357527Sjoerg if (eflag) 34457527Sjoerg putchar(ch); 34510352Sjoerg morse(ch); 34657527Sjoerg } 34710352Sjoerg } 34857527Sjoerg if (device) 34957527Sjoerg tcsetattr(line, TCSANOW, &otty); 35010352Sjoerg exit(0); 3512490Sjkh} 3522490Sjkh 35310352Sjoergvoid 35410352Sjoergmorse(char c) 3552490Sjkh{ 35654622Sbillf const struct morsetab *m; 35710352Sjoerg 35829018Sache if (isalpha((unsigned char)c)) 35929018Sache c = tolower((unsigned char)c); 36010352Sjoerg if ((c == '\r') || (c == '\n')) 36110352Sjoerg c = ' '; 36210352Sjoerg if (c == ' ') { 36310352Sjoerg if (pflag) { 36410352Sjoerg play(" "); 36510352Sjoerg return; 36657527Sjoerg } else if (device) { 36757527Sjoerg ttyout(" "); 36857527Sjoerg return; 36910352Sjoerg } else { 37010352Sjoerg show(""); 37110352Sjoerg return; 37210352Sjoerg } 37310352Sjoerg } 37410352Sjoerg for (m = ((unsigned char)c < 0x80? mtab: hightab); 37510352Sjoerg m->inchar != '\0'; 37610352Sjoerg m++) { 37710352Sjoerg if (m->inchar == c) { 37810352Sjoerg if (pflag) { 37910352Sjoerg play(m->morse); 38057527Sjoerg } else if (device) { 38157527Sjoerg ttyout(m->morse); 38210352Sjoerg } else 38310352Sjoerg show(m->morse); 38410352Sjoerg } 38510352Sjoerg } 3862490Sjkh} 3872490Sjkh 38810352Sjoergvoid 38910352Sjoergshow(const char *s) 3902490Sjkh{ 3912490Sjkh if (sflag) 3922490Sjkh printf(" %s", s); 39310352Sjoerg else 39410352Sjoerg for (; *s; ++s) 39510352Sjoerg printf(" %s", *s == '.' ? "dit" : "dah"); 39610352Sjoerg printf("\n"); 3972490Sjkh} 39810352Sjoerg 39910352Sjoergvoid 40010352Sjoergplay(const char *s) 40110352Sjoerg{ 40210352Sjoerg#ifdef SPEAKER 40310352Sjoerg const char *c; 40410352Sjoerg 40510352Sjoerg for (c = s; *c != '\0'; c++) { 40629018Sache switch (*c) { 40710352Sjoerg case '.': 40810352Sjoerg sound.frequency = freq; 40910352Sjoerg sound.duration = dot_clock; 41010352Sjoerg break; 41110352Sjoerg case '-': 41210352Sjoerg sound.frequency = freq; 41310352Sjoerg sound.duration = dot_clock * DASH_LEN; 41410352Sjoerg break; 41510352Sjoerg case ' ': 41610352Sjoerg sound.frequency = 0; 41710352Sjoerg sound.duration = dot_clock * WORD_SPACE; 41810352Sjoerg break; 41910352Sjoerg default: 42010352Sjoerg sound.duration = 0; 42110352Sjoerg } 42210352Sjoerg if (sound.duration) { 42310352Sjoerg if (ioctl(spkr, SPKRTONE, &sound) == -1) { 42410352Sjoerg perror("ioctl play"); 42510352Sjoerg exit(1); 42610352Sjoerg } 42710352Sjoerg } 42810352Sjoerg sound.frequency = 0; 42910352Sjoerg sound.duration = dot_clock; 43010352Sjoerg if (ioctl(spkr, SPKRTONE, &sound) == -1) { 43110352Sjoerg perror("ioctl rest"); 43210352Sjoerg exit(1); 43310352Sjoerg } 43410352Sjoerg } 43510352Sjoerg sound.frequency = 0; 43610352Sjoerg sound.duration = dot_clock * CHAR_SPACE; 43710352Sjoerg ioctl(spkr, SPKRTONE, &sound); 43810352Sjoerg#endif 43910352Sjoerg} 44057527Sjoerg 44157527Sjoergvoid 44257527Sjoergttyout(const char *s) 44357527Sjoerg{ 44457527Sjoerg const char *c; 44557527Sjoerg int duration, on, lflags; 44657527Sjoerg 44757527Sjoerg for (c = s; *c != '\0'; c++) { 44857527Sjoerg switch (*c) { 44957527Sjoerg case '.': 45057527Sjoerg on = 1; 45157527Sjoerg duration = dot_clock; 45257527Sjoerg break; 45357527Sjoerg case '-': 45457527Sjoerg on = 1; 45557527Sjoerg duration = dot_clock * DASH_LEN; 45657527Sjoerg break; 45757527Sjoerg case ' ': 45857527Sjoerg on = 0; 45957527Sjoerg duration = dot_clock * WORD_SPACE; 46057527Sjoerg break; 46157527Sjoerg default: 46257527Sjoerg on = 0; 46357527Sjoerg duration = 0; 46457527Sjoerg } 46557527Sjoerg if (on) { 46657527Sjoerg ioctl(line, TIOCMGET, &lflags); 46757527Sjoerg lflags |= TIOCM_RTS; 46857527Sjoerg ioctl(line, TIOCMSET, &lflags); 46957527Sjoerg } 47057527Sjoerg duration *= 10000; 47157527Sjoerg if (duration) 47257527Sjoerg usleep(duration); 47357527Sjoerg ioctl(line, TIOCMGET, &lflags); 47457527Sjoerg lflags &= ~TIOCM_RTS; 47557527Sjoerg ioctl(line, TIOCMSET, &lflags); 47657527Sjoerg duration = dot_clock * 10000; 47757527Sjoerg usleep(duration); 47857527Sjoerg } 47957527Sjoerg duration = dot_clock * CHAR_SPACE * 10000; 48057527Sjoerg usleep(duration); 48157527Sjoerg} 48257527Sjoerg 48357527Sjoergvoid 48457527Sjoergsighandler(int signo) 48557527Sjoerg{ 48657527Sjoerg 48757527Sjoerg ioctl(line, TIOCMSET, &olflags); 48857527Sjoerg tcsetattr(line, TCSANOW, &otty); 48957527Sjoerg 49057527Sjoerg signal(signo, SIG_DFL); 49157527Sjoerg (void)kill(getpid(), signo); 49257527Sjoerg} 493