morse.c revision 73349
1159720Syar/* 2159720Syar * Copyright (c) 1988, 1993 3159720Syar * The Regents of the University of California. All rights reserved. 4159720Syar * 5159720Syar * Redistribution and use in source and binary forms, with or without 6159720Syar * modification, are permitted provided that the following conditions 7159720Syar * are met: 8159720Syar * 1. Redistributions of source code must retain the above copyright 9159720Syar * notice, this list of conditions and the following disclaimer. 10159720Syar * 2. Redistributions in binary form must reproduce the above copyright 11159720Syar * notice, this list of conditions and the following disclaimer in the 12159720Syar * documentation and/or other materials provided with the distribution. 13159720Syar * 3. All advertising materials mentioning features or use of this software 14159720Syar * must display the following acknowledgement: 15159720Syar * This product includes software developed by the University of 16159720Syar * California, Berkeley and its contributors. 17159720Syar * 4. Neither the name of the University nor the names of its contributors 18159720Syar * may be used to endorse or promote products derived from this software 19159720Syar * without specific prior written permission. 20159720Syar * 21159720Syar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22159720Syar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23159720Syar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24159720Syar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25159720Syar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26159720Syar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27159720Syar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28159720Syar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29159720Syar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30159720Syar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31159720Syar * SUCH DAMAGE. 32159720Syar */ 33159720Syar 34159720Syar/* 35159720Syar * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM) 36159720Syar * <lyndon@orthanc.com> 37159720Syar */ 38159720Syar 39159720Syar#ifndef lint 40159720Syarstatic const char copyright[] = 41159720Syar"@(#) Copyright (c) 1988, 1993\n\ 42159720Syar The Regents of the University of California. All rights reserved.\n"; 43159720Syar#endif /* not lint */ 44159720Syar 45159720Syar#ifndef lint 46159720Syar#if 0 47159720Syarstatic char sccsid[] = "@(#)morse.c 8.1 (Berkeley) 5/31/93"; 48159720Syar#endif 49159720Syarstatic const char rcsid[] = 50159720Syar "$FreeBSD: head/games/morse/morse.c 73349 2001-03-02 16:52:14Z ru $"; 51159720Syar#endif /* not lint */ 52159720Syar 53159720Syar#include <sys/time.h> 54159720Syar 55159720Syar#include <ctype.h> 56159720Syar#include <fcntl.h> 57159720Syar#include <locale.h> 58159720Syar#include <signal.h> 59159720Syar#include <stdio.h> 60159720Syar#include <stdlib.h> 61159720Syar#include <string.h> 62159720Syar#include <termios.h> 63159720Syar#include <unistd.h> 64159720Syar 65159720Syar#ifdef SPEAKER 66159720Syar#include <machine/speaker.h> 67159720Syar#endif 68159720Syar 69159720Syarstruct morsetab { 70159720Syar char inchar; 71159720Syar char *morse; 72159720Syar}; 73159720Syar 74159720Syarstatic const struct morsetab mtab[] = { 75159720Syar 76159720Syar /* letters */ 77159720Syar 78159720Syar {'a', ".-"}, 79159720Syar {'b', "-..."}, 80159720Syar {'c', "-.-."}, 81159720Syar {'d', "-.."}, 82159720Syar {'e', "."}, 83159720Syar {'f', "..-."}, 84159720Syar {'g', "--."}, 85159720Syar {'h', "...."}, 86159720Syar {'i', ".."}, 87159720Syar {'j', ".---"}, 88159720Syar {'k', "-.-"}, 89159720Syar {'l', ".-.."}, 90159720Syar {'m', "--"}, 91159720Syar {'n', "-."}, 92159720Syar {'o', "---"}, 93159720Syar {'p', ".--."}, 94159720Syar {'q', "--.-"}, 95159720Syar {'r', ".-."}, 96159720Syar {'s', "..."}, 97159720Syar {'t', "-"}, 98159720Syar {'u', "..-"}, 99159720Syar {'v', "...-"}, 100159720Syar {'w', ".--"}, 101159720Syar {'x', "-..-"}, 102159720Syar {'y', "-.--"}, 103159720Syar {'z', "--.."}, 104159720Syar 105159720Syar /* digits */ 106159720Syar 107159720Syar {'0', "-----"}, 108159720Syar {'1', ".----"}, 109159720Syar {'2', "..---"}, 110159720Syar {'3', "...--"}, 111159720Syar {'4', "....-"}, 112159720Syar {'5', "....."}, 113159720Syar {'6', "-...."}, 114159720Syar {'7', "--..."}, 115159720Syar {'8', "---.."}, 116159720Syar {'9', "----."}, 117159720Syar 118159720Syar /* punctuation */ 119159720Syar 120159720Syar {',', "--..--"}, 121159720Syar {'.', ".-.-.-"}, 122159720Syar {'?', "..--.."}, 123159720Syar {'/', "-..-."}, 124159720Syar {'-', "-....-"}, 125159720Syar {'=', "-...-"}, /* BT */ 126159720Syar {':', "---..."}, 127159720Syar {';', "-.-.-."}, 128159720Syar {'(', "-.--."}, /* KN */ 129 {')', "-.--.-"}, 130 {'$', "...-..-"}, 131 {'+', ".-.-."}, /* AR */ 132 133 /* prosigns without already assigned values */ 134 135 {'#', ".-..."}, /* AS */ 136 {'@', "...-.-"}, /* SK */ 137 {'*', "...-."}, /* VE */ 138 {'%', "-...-.-"}, /* BK */ 139 140 {'\0', ""} 141}; 142 143 144static const struct morsetab iso8859tab[] = { 145 {'�', ".--.-"}, 146 {'�', ".--.-"}, 147 {'�', ".--.-"}, 148 {'�', ".-.-"}, 149 {'�', "-.-.."}, 150 {'�', "..-.."}, 151 {'�', "..-.."}, 152 {'�', "-..-."}, 153 {'�', "---."}, 154 {'�', "..--"}, 155 156 {'\0', ""} 157}; 158 159static const struct morsetab koi8rtab[] = { 160 /* 161 * the cyrillic alphabet; you'll need a KOI8R font in order 162 * to see the actual characters 163 */ 164 {'�', ".-"}, /* a */ 165 {'�', "-..."}, /* be */ 166 {'�', ".--"}, /* ve */ 167 {'�', "--."}, /* ge */ 168 {'�', "-.."}, /* de */ 169 {'�', "."}, /* ye */ 170 {'�', "."}, /* yo, the same as ye */ 171 {'�', "...-"}, /* she */ 172 {'�', "--.."}, /* ze */ 173 {'�', ".."}, /* i */ 174 {'�', ".---"}, /* i kratkoye */ 175 {'�', "-.-"}, /* ka */ 176 {'�', ".-.."}, /* el */ 177 {'�', "--"}, /* em */ 178 {'�', "-."}, /* en */ 179 {'�', "---"}, /* o */ 180 {'�', ".--."}, /* pe */ 181 {'�', ".-."}, /* er */ 182 {'�', "..."}, /* es */ 183 {'�', "-"}, /* te */ 184 {'�', "..-"}, /* u */ 185 {'�', "..-."}, /* ef */ 186 {'�', "...."}, /* kha */ 187 {'�', "-.-."}, /* ce */ 188 {'�', "---."}, /* che */ 189 {'�', "----"}, /* sha */ 190 {'�', "--.-"}, /* shcha */ 191 {'�', "-.--"}, /* yi */ 192 {'�', "-..-"}, /* myakhkij znak */ 193 {'�', "..-.."}, /* ae */ 194 {'�', "..--"}, /* yu */ 195 {'�', ".-.-"}, /* ya */ 196 197 {'\0', ""} 198}; 199 200void show(const char *), play(const char *), morse(char); 201void ttyout(const char *); 202void sighandler(int); 203 204#define GETOPTOPTS "d:ef:sw:" 205#define USAGE \ 206"usage: morse [-s] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n" 207 208static int pflag, sflag, eflag; 209static int wpm = 20; /* words per minute */ 210#define FREQUENCY 600 211static int freq = FREQUENCY; 212static char *device; /* for tty-controlled generator */ 213 214#define DASH_LEN 3 215#define CHAR_SPACE 3 216#define WORD_SPACE (7 - CHAR_SPACE - 1) 217static float dot_clock; 218int spkr, line; 219struct termios otty, ntty; 220int olflags; 221 222#ifdef SPEAKER 223tone_t sound; 224#undef GETOPTOPTS 225#define GETOPTOPTS "d:ef:psw:" 226#undef USAGE 227#define USAGE \ 228"usage: morse [-s] [-p] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n" 229#endif 230 231static const struct morsetab *hightab = iso8859tab; 232 233int 234main(int argc, char **argv) 235{ 236 int ch, lflags; 237 char *p; 238 239 while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1) 240 switch ((char) ch) { 241 case 'd': 242 device = optarg; 243 break; 244 case 'e': 245 eflag = 1; 246 setvbuf(stdout, 0, _IONBF, 0); 247 break; 248 case 'f': 249 freq = atoi(optarg); 250 break; 251#ifdef SPEAKER 252 case 'p': 253 pflag = 1; 254 break; 255#endif 256 case 's': 257 sflag = 1; 258 break; 259 case 'w': 260 wpm = atoi(optarg); 261 break; 262 case '?': 263 default: 264 fputs(USAGE, stderr); 265 exit(1); 266 } 267 if ((pflag || device) && sflag) { 268 fputs("morse: only one of -p, -d and -s allowed\n", stderr); 269 exit(1); 270 } 271 if ((pflag || device) && ((wpm < 1) || (wpm > 60))) { 272 fputs("morse: insane speed\n", stderr); 273 exit(1); 274 } 275 if ((pflag || device) && (freq == 0)) 276 freq = FREQUENCY; 277 278#ifdef SPEAKER 279 if (pflag) { 280 if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) { 281 perror(SPEAKER); 282 exit(1); 283 } 284 } else 285#endif 286 if (device) { 287 if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) { 288 perror("open tty line"); 289 exit(1); 290 } 291 if (tcgetattr(line, &otty) == -1) { 292 perror("tcgetattr() failed"); 293 exit(1); 294 } 295 ntty = otty; 296 ntty.c_cflag |= CLOCAL; 297 tcsetattr(line, TCSANOW, &ntty); 298 lflags = fcntl(line, F_GETFL); 299 lflags &= ~O_NONBLOCK; 300 fcntl(line, F_SETFL, &lflags); 301 ioctl(line, TIOCMGET, &lflags); 302 lflags &= ~TIOCM_RTS; 303 olflags = lflags; 304 ioctl(line, TIOCMSET, &lflags); 305 (void)signal(SIGHUP, sighandler); 306 (void)signal(SIGINT, sighandler); 307 (void)signal(SIGQUIT, sighandler); 308 (void)signal(SIGTERM, sighandler); 309 } 310 if (pflag || device) { 311 dot_clock = wpm / 2.4; /* dots/sec */ 312 dot_clock = 1 / dot_clock; /* duration of a dot */ 313 dot_clock = dot_clock / 2; /* dot_clock runs at twice */ 314 /* the dot rate */ 315 dot_clock = dot_clock * 100; /* scale for ioctl */ 316 } 317 318 argc -= optind; 319 argv += optind; 320 321 if(((p = getenv("LC_ALL")) && *p) || 322 ((p = getenv("LC_CTYPE")) && *p) || 323 ((p = getenv("LANG")) && *p)) { 324 if(strlen(p) >= sizeof(".KOI8-R") && 325 strcasecmp(&p[strlen(p) + 1 - sizeof(".KOI8-R")], ".KOI8-R") == 0) 326 hightab = koi8rtab; 327 } 328 (void) setlocale(LC_CTYPE, ""); 329 330 if (*argv) { 331 do { 332 for (p = *argv; *p; ++p) { 333 if (eflag) 334 putchar(*p); 335 morse(*p); 336 } 337 if (eflag) 338 putchar(' '); 339 morse(' '); 340 } while (*++argv); 341 } else { 342 while ((ch = getchar()) != EOF) { 343 if (eflag) 344 putchar(ch); 345 morse(ch); 346 } 347 } 348 if (device) 349 tcsetattr(line, TCSANOW, &otty); 350 exit(0); 351} 352 353void 354morse(char c) 355{ 356 const struct morsetab *m; 357 358 if (isalpha((unsigned char)c)) 359 c = tolower((unsigned char)c); 360 if ((c == '\r') || (c == '\n')) 361 c = ' '; 362 if (c == ' ') { 363 if (pflag) { 364 play(" "); 365 return; 366 } else if (device) { 367 ttyout(" "); 368 return; 369 } else { 370 show(""); 371 return; 372 } 373 } 374 for (m = ((unsigned char)c < 0x80? mtab: hightab); 375 m->inchar != '\0'; 376 m++) { 377 if (m->inchar == c) { 378 if (pflag) { 379 play(m->morse); 380 } else if (device) { 381 ttyout(m->morse); 382 } else 383 show(m->morse); 384 } 385 } 386} 387 388void 389show(const char *s) 390{ 391 if (sflag) 392 printf(" %s", s); 393 else 394 for (; *s; ++s) 395 printf(" %s", *s == '.' ? "dit" : "dah"); 396 printf("\n"); 397} 398 399void 400play(const char *s) 401{ 402#ifdef SPEAKER 403 const char *c; 404 405 for (c = s; *c != '\0'; c++) { 406 switch (*c) { 407 case '.': 408 sound.frequency = freq; 409 sound.duration = dot_clock; 410 break; 411 case '-': 412 sound.frequency = freq; 413 sound.duration = dot_clock * DASH_LEN; 414 break; 415 case ' ': 416 sound.frequency = 0; 417 sound.duration = dot_clock * WORD_SPACE; 418 break; 419 default: 420 sound.duration = 0; 421 } 422 if (sound.duration) { 423 if (ioctl(spkr, SPKRTONE, &sound) == -1) { 424 perror("ioctl play"); 425 exit(1); 426 } 427 } 428 sound.frequency = 0; 429 sound.duration = dot_clock; 430 if (ioctl(spkr, SPKRTONE, &sound) == -1) { 431 perror("ioctl rest"); 432 exit(1); 433 } 434 } 435 sound.frequency = 0; 436 sound.duration = dot_clock * CHAR_SPACE; 437 ioctl(spkr, SPKRTONE, &sound); 438#endif 439} 440 441void 442ttyout(const char *s) 443{ 444 const char *c; 445 int duration, on, lflags; 446 447 for (c = s; *c != '\0'; c++) { 448 switch (*c) { 449 case '.': 450 on = 1; 451 duration = dot_clock; 452 break; 453 case '-': 454 on = 1; 455 duration = dot_clock * DASH_LEN; 456 break; 457 case ' ': 458 on = 0; 459 duration = dot_clock * WORD_SPACE; 460 break; 461 default: 462 on = 0; 463 duration = 0; 464 } 465 if (on) { 466 ioctl(line, TIOCMGET, &lflags); 467 lflags |= TIOCM_RTS; 468 ioctl(line, TIOCMSET, &lflags); 469 } 470 duration *= 10000; 471 if (duration) 472 usleep(duration); 473 ioctl(line, TIOCMGET, &lflags); 474 lflags &= ~TIOCM_RTS; 475 ioctl(line, TIOCMSET, &lflags); 476 duration = dot_clock * 10000; 477 usleep(duration); 478 } 479 duration = dot_clock * CHAR_SPACE * 10000; 480 usleep(duration); 481} 482 483void 484sighandler(int signo) 485{ 486 487 ioctl(line, TIOCMSET, &olflags); 488 tcsetattr(line, TCSANOW, &otty); 489 490 signal(signo, SIG_DFL); 491 (void)kill(getpid(), signo); 492} 493