morse.c revision 126044
1114987Speter/* 2114987Speter * Copyright (c) 1988, 1993 3114987Speter * The Regents of the University of California. All rights reserved. 4114987Speter * 5114987Speter * Redistribution and use in source and binary forms, with or without 6114987Speter * modification, are permitted provided that the following conditions 7114987Speter * are met: 8114987Speter * 1. Redistributions of source code must retain the above copyright 9114987Speter * notice, this list of conditions and the following disclaimer. 10114987Speter * 2. Redistributions in binary form must reproduce the above copyright 11114987Speter * notice, this list of conditions and the following disclaimer in the 12114987Speter * documentation and/or other materials provided with the distribution. 13114987Speter * 3. All advertising materials mentioning features or use of this software 14114987Speter * must display the following acknowledgement: 15114987Speter * This product includes software developed by the University of 16114987Speter * California, Berkeley and its contributors. 17114987Speter * 4. Neither the name of the University nor the names of its contributors 18114987Speter * may be used to endorse or promote products derived from this software 19114987Speter * without specific prior written permission. 20114987Speter * 21114987Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22114987Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23114987Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24114987Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25114987Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26114987Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27114987Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28114987Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29114987Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30114987Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31114987Speter * SUCH DAMAGE. 32114987Speter */ 33114987Speter 34114987Speter/* 35114987Speter * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM) 36114987Speter * <lyndon@orthanc.com> 37114987Speter */ 38118031Sobrien 39118031Sobrien#ifndef lint 40118031Sobrienstatic const char copyright[] = 41114987Speter"@(#) Copyright (c) 1988, 1993\n\ 42114987Speter The Regents of the University of California. All rights reserved.\n"; 43114987Speter#endif /* not lint */ 44114987Speter 45114987Speter#ifndef lint 46114987Speter#if 0 47114987Speterstatic char sccsid[] = "@(#)morse.c 8.1 (Berkeley) 5/31/93"; 48114987Speter#endif 49114987Speterstatic const char rcsid[] = 50114987Speter "$FreeBSD: head/games/morse/morse.c 126044 2004-02-20 13:46:39Z fanf $"; 51114987Speter#endif /* not lint */ 52114987Speter 53114987Speter#include <sys/time.h> 54114987Speter 55114987Speter#include <ctype.h> 56114987Speter#include <fcntl.h> 57114987Speter#include <langinfo.h> 58114987Speter#include <locale.h> 59114987Speter#include <signal.h> 60114987Speter#include <stdio.h> 61114987Speter#include <stdlib.h> 62114987Speter#include <string.h> 63114987Speter#include <termios.h> 64114987Speter#include <unistd.h> 65114987Speter 66114987Speter#ifdef SPEAKER 67114987Speter#include <machine/speaker.h> 68114987Speter#endif 69114987Speter 70114987Speterstruct morsetab { 71114987Speter char inchar; 72114987Speter char *morse; 73114987Speter}; 74114987Speter 75114987Speterstatic const struct morsetab mtab[] = { 76114987Speter 77114987Speter /* letters */ 78114987Speter 79122849Speter {'a', ".-"}, 80114987Speter {'b', "-..."}, 81114987Speter {'c', "-.-."}, 82114987Speter {'d', "-.."}, 83114987Speter {'e', "."}, 84114987Speter {'f', "..-."}, 85119336Speter {'g', "--."}, 86114987Speter {'h', "...."}, 87114987Speter {'i', ".."}, 88114987Speter {'j', ".---"}, 89114987Speter {'k', "-.-"}, 90114987Speter {'l', ".-.."}, 91114987Speter {'m', "--"}, 92114987Speter {'n', "-."}, 93114987Speter {'o', "---"}, 94114987Speter {'p', ".--."}, 95114987Speter {'q', "--.-"}, 96114987Speter {'r', ".-."}, 97114987Speter {'s', "..."}, 98114987Speter {'t', "-"}, 99114987Speter {'u', "..-"}, 100114987Speter {'v', "...-"}, 101114987Speter {'w', ".--"}, 102114987Speter {'x', "-..-"}, 103114987Speter {'y', "-.--"}, 104114987Speter {'z', "--.."}, 105114987Speter 106114987Speter /* digits */ 107114987Speter 108114987Speter {'0', "-----"}, 109114987Speter {'1', ".----"}, 110114987Speter {'2', "..---"}, 111114987Speter {'3', "...--"}, 112114987Speter {'4', "....-"}, 113114987Speter {'5', "....."}, 114114987Speter {'6', "-...."}, 115114987Speter {'7', "--..."}, 116114987Speter {'8', "---.."}, 117114987Speter {'9', "----."}, 118114987Speter 119114987Speter /* punctuation */ 120114987Speter 121114987Speter {',', "--..--"}, 122114987Speter {'.', ".-.-.-"}, 123114987Speter {'"', ".-..-."}, 124114987Speter {'!', "..--."}, 125114987Speter {'?', "..--.."}, 126114987Speter {'/', "-..-."}, 127114987Speter {'-', "-....-"}, 128114987Speter {'=', "-...-"}, /* BT */ 129114987Speter {':', "---..."}, 130114987Speter {';', "-.-.-."}, 131114987Speter {'(', "-.--."}, /* KN */ 132114987Speter {')', "-.--.-"}, 133114987Speter {'$', "...-..-"}, 134114987Speter {'+', ".-.-."}, /* AR */ 135114987Speter {'@', ".--.-."}, /* AC */ 136114987Speter 137114987Speter /* prosigns without already assigned values */ 138114987Speter 139114987Speter {'#', ".-..."}, /* AS */ 140114987Speter {'&', "...-.-"}, /* SK */ 141114987Speter {'*', "...-."}, /* VE */ 142114987Speter {'%', "-...-.-"}, /* BK */ 143114987Speter 144114987Speter {'\0', ""} 145114987Speter}; 146114987Speter 147114987Speter 148114987Speterstatic const struct morsetab iso8859tab[] = { 149114987Speter {'�', ".--.-"}, 150114987Speter {'�', ".--.-"}, 151114987Speter {'�', ".--.-"}, 152114987Speter {'�', ".-.-"}, 153114987Speter {'�', "-.-.."}, 154114987Speter {'�', "..-.."}, 155114987Speter {'�', "..-.."}, 156114987Speter {'�', "-..-."}, 157114987Speter {'�', "---."}, 158114987Speter {'�', "..--"}, 159114987Speter 160114987Speter {'\0', ""} 161114987Speter}; 162114987Speter 163114987Speterstatic const struct morsetab koi8rtab[] = { 164114987Speter /* 165114987Speter * the cyrillic alphabet; you'll need a KOI8R font in order 166114987Speter * to see the actual characters 167114987Speter */ 168114987Speter {'�', ".-"}, /* a */ 169114987Speter {'�', "-..."}, /* be */ 170114987Speter {'�', ".--"}, /* ve */ 171114987Speter {'�', "--."}, /* ge */ 172114987Speter {'�', "-.."}, /* de */ 173114987Speter {'�', "."}, /* ye */ 174114987Speter {'�', "."}, /* yo, the same as ye */ 175114987Speter {'�', "...-"}, /* she */ 176114987Speter {'�', "--.."}, /* ze */ 177114987Speter {'�', ".."}, /* i */ 178114987Speter {'�', ".---"}, /* i kratkoye */ 179114987Speter {'�', "-.-"}, /* ka */ 180114987Speter {'�', ".-.."}, /* el */ 181114987Speter {'�', "--"}, /* em */ 182114987Speter {'�', "-."}, /* en */ 183114987Speter {'�', "---"}, /* o */ 184114987Speter {'�', ".--."}, /* pe */ 185114987Speter {'�', ".-."}, /* er */ 186114987Speter {'�', "..."}, /* es */ 187114987Speter {'�', "-"}, /* te */ 188114987Speter {'�', "..-"}, /* u */ 189114987Speter {'�', "..-."}, /* ef */ 190114987Speter {'�', "...."}, /* kha */ 191114987Speter {'�', "-.-."}, /* ce */ 192114987Speter {'�', "---."}, /* che */ 193114987Speter {'�', "----"}, /* sha */ 194114987Speter {'�', "--.-"}, /* shcha */ 195114987Speter {'�', "-.--"}, /* yi */ 196114987Speter {'�', "-..-"}, /* myakhkij znak */ 197114987Speter {'�', "..-.."}, /* ae */ 198114987Speter {'�', "..--"}, /* yu */ 199114987Speter {'�', ".-.-"}, /* ya */ 200114987Speter 201114987Speter {'\0', ""} 202114987Speter}; 203114987Speter 204114987Spetervoid show(const char *), play(const char *), morse(char); 205114987Spetervoid ttyout(const char *); 206114987Spetervoid sighandler(int); 207114987Speter 208114987Speter#define GETOPTOPTS "d:ef:lsw:" 209114987Speter#define USAGE \ 210114987Speter"usage: morse [-els] [-d device] [-w speed] [-f frequency] [string ...]\n" 211114987Speter 212114987Speterstatic int pflag, lflag, sflag, eflag; 213114987Speterstatic int wpm = 20; /* words per minute */ 214114987Speter#define FREQUENCY 600 215114987Speterstatic int freq = FREQUENCY; 216114987Speterstatic char *device; /* for tty-controlled generator */ 217114987Speter 218114987Speter#define DASH_LEN 3 219114987Speter#define CHAR_SPACE 3 220114987Speter#define WORD_SPACE (7 - CHAR_SPACE - 1) 221114987Speterstatic float dot_clock; 222114987Speterint spkr, line; 223114987Speterstruct termios otty, ntty; 224114987Speterint olflags; 225114987Speter 226114987Speter#ifdef SPEAKER 227114987Spetertone_t sound; 228114987Speter#undef GETOPTOPTS 229114987Speter#define GETOPTOPTS "d:ef:lpsw:" 230114987Speter#undef USAGE 231114987Speter#define USAGE \ 232114987Speter"usage: morse [-s] [-p] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n" 233114987Speter#endif 234114987Speter 235114987Speterstatic const struct morsetab *hightab; 236114987Speter 237114987Speterint 238114987Spetermain(int argc, char **argv) 239114987Speter{ 240114987Speter int ch, lflags; 241114987Speter char *p, *codeset; 242114987Speter 243114987Speter while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1) 244114987Speter switch ((char) ch) { 245114987Speter case 'd': 246114987Speter device = optarg; 247114987Speter break; 248114987Speter case 'e': 249114987Speter eflag = 1; 250114987Speter setvbuf(stdout, 0, _IONBF, 0); 251114987Speter break; 252114987Speter case 'f': 253114987Speter freq = atoi(optarg); 254119336Speter break; 255114987Speter case 'l': 256114987Speter lflag = 1; 257114987Speter break; 258114987Speter#ifdef SPEAKER 259114987Speter case 'p': 260114987Speter pflag = 1; 261114987Speter break; 262114987Speter#endif 263114987Speter case 's': 264120346Speter sflag = 1; 265114987Speter break; 266114987Speter case 'w': 267114987Speter wpm = atoi(optarg); 268114987Speter break; 269114987Speter case '?': 270114987Speter default: 271120346Speter fputs(USAGE, stderr); 272114987Speter exit(1); 273114987Speter } 274114987Speter if (sflag && lflag) { 275114987Speter fputs("morse: only one of -l and -s allowed\n", stderr); 276 exit(1); 277 } 278 if ((pflag || device) && (sflag || lflag)) { 279 fputs("morse: only one of -p, -d and -l, -s allowed\n", stderr); 280 exit(1); 281 } 282 if ((pflag || device) && ((wpm < 1) || (wpm > 60))) { 283 fputs("morse: insane speed\n", stderr); 284 exit(1); 285 } 286 if ((pflag || device) && (freq == 0)) 287 freq = FREQUENCY; 288 289#ifdef SPEAKER 290 if (pflag) { 291 if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) { 292 perror(SPEAKER); 293 exit(1); 294 } 295 } else 296#endif 297 if (device) { 298 if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) { 299 perror("open tty line"); 300 exit(1); 301 } 302 if (tcgetattr(line, &otty) == -1) { 303 perror("tcgetattr() failed"); 304 exit(1); 305 } 306 ntty = otty; 307 ntty.c_cflag |= CLOCAL; 308 tcsetattr(line, TCSANOW, &ntty); 309 lflags = fcntl(line, F_GETFL); 310 lflags &= ~O_NONBLOCK; 311 fcntl(line, F_SETFL, &lflags); 312 ioctl(line, TIOCMGET, &lflags); 313 lflags &= ~TIOCM_RTS; 314 olflags = lflags; 315 ioctl(line, TIOCMSET, &lflags); 316 (void)signal(SIGHUP, sighandler); 317 (void)signal(SIGINT, sighandler); 318 (void)signal(SIGQUIT, sighandler); 319 (void)signal(SIGTERM, sighandler); 320 } 321 if (pflag || device) { 322 dot_clock = wpm / 2.4; /* dots/sec */ 323 dot_clock = 1 / dot_clock; /* duration of a dot */ 324 dot_clock = dot_clock / 2; /* dot_clock runs at twice */ 325 /* the dot rate */ 326 dot_clock = dot_clock * 100; /* scale for ioctl */ 327 } 328 329 argc -= optind; 330 argv += optind; 331 332 if (setlocale(LC_CTYPE, "") != NULL && 333 *(codeset = nl_langinfo(CODESET)) != '\0') { 334 if (strcmp(codeset, "KOI8-R") == 0) 335 hightab = koi8rtab; 336 else if (strcmp(codeset, "ISO8859-1") == 0 || 337 strcmp(codeset, "ISO8859-15") == 0) 338 hightab = iso8859tab; 339 } 340 341 if (lflag) 342 printf("m"); 343 if (*argv) { 344 do { 345 for (p = *argv; *p; ++p) { 346 if (eflag) 347 putchar(*p); 348 morse(*p); 349 } 350 if (eflag) 351 putchar(' '); 352 morse(' '); 353 } while (*++argv); 354 } else { 355 while ((ch = getchar()) != EOF) { 356 if (eflag) 357 putchar(ch); 358 morse(ch); 359 } 360 } 361 if (device) 362 tcsetattr(line, TCSANOW, &otty); 363 exit(0); 364} 365 366void 367morse(char c) 368{ 369 const struct morsetab *m; 370 371 if (isalpha((unsigned char)c)) 372 c = tolower((unsigned char)c); 373 if ((c == '\r') || (c == '\n')) 374 c = ' '; 375 if (c == ' ') { 376 if (pflag) 377 play(" "); 378 else if (device) 379 ttyout(" "); 380 else if (lflag) 381 printf("\n"); 382 else 383 show(""); 384 return; 385 } 386 for (m = ((unsigned char)c < 0x80? mtab: hightab); 387 m != NULL && m->inchar != '\0'; 388 m++) { 389 if (m->inchar == c) { 390 if (pflag) { 391 play(m->morse); 392 } else if (device) { 393 ttyout(m->morse); 394 } else 395 show(m->morse); 396 } 397 } 398} 399 400void 401show(const char *s) 402{ 403 if (lflag) { 404 printf("%s ", s); 405 } else if (sflag) { 406 printf(" %s\n", s); 407 } else { 408 for (; *s; ++s) 409 printf(" %s", *s == '.' ? "dit" : "dah"); 410 printf("\n"); 411 } 412} 413 414void 415play(const char *s) 416{ 417#ifdef SPEAKER 418 const char *c; 419 420 for (c = s; *c != '\0'; c++) { 421 switch (*c) { 422 case '.': 423 sound.frequency = freq; 424 sound.duration = dot_clock; 425 break; 426 case '-': 427 sound.frequency = freq; 428 sound.duration = dot_clock * DASH_LEN; 429 break; 430 case ' ': 431 sound.frequency = 0; 432 sound.duration = dot_clock * WORD_SPACE; 433 break; 434 default: 435 sound.duration = 0; 436 } 437 if (sound.duration) { 438 if (ioctl(spkr, SPKRTONE, &sound) == -1) { 439 perror("ioctl play"); 440 exit(1); 441 } 442 } 443 sound.frequency = 0; 444 sound.duration = dot_clock; 445 if (ioctl(spkr, SPKRTONE, &sound) == -1) { 446 perror("ioctl rest"); 447 exit(1); 448 } 449 } 450 sound.frequency = 0; 451 sound.duration = dot_clock * CHAR_SPACE; 452 ioctl(spkr, SPKRTONE, &sound); 453#endif 454} 455 456void 457ttyout(const char *s) 458{ 459 const char *c; 460 int duration, on, lflags; 461 462 for (c = s; *c != '\0'; c++) { 463 switch (*c) { 464 case '.': 465 on = 1; 466 duration = dot_clock; 467 break; 468 case '-': 469 on = 1; 470 duration = dot_clock * DASH_LEN; 471 break; 472 case ' ': 473 on = 0; 474 duration = dot_clock * WORD_SPACE; 475 break; 476 default: 477 on = 0; 478 duration = 0; 479 } 480 if (on) { 481 ioctl(line, TIOCMGET, &lflags); 482 lflags |= TIOCM_RTS; 483 ioctl(line, TIOCMSET, &lflags); 484 } 485 duration *= 10000; 486 if (duration) 487 usleep(duration); 488 ioctl(line, TIOCMGET, &lflags); 489 lflags &= ~TIOCM_RTS; 490 ioctl(line, TIOCMSET, &lflags); 491 duration = dot_clock * 10000; 492 usleep(duration); 493 } 494 duration = dot_clock * CHAR_SPACE * 10000; 495 usleep(duration); 496} 497 498void 499sighandler(int signo) 500{ 501 502 ioctl(line, TIOCMSET, &olflags); 503 tcsetattr(line, TCSANOW, &otty); 504 505 signal(signo, SIG_DFL); 506 (void)kill(getpid(), signo); 507} 508