1 /* 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#) Copyright (c) 1988, 1993 The Regents of the University of California. All rights reserved. 34 * @(#)morse.c 8.1 (Berkeley) 5/31/93 35 * $FreeBSD: src/games/morse/morse.c,v 1.12.2.2 2002/03/12 17:45:15 phantom Exp $ 36 * $DragonFly: src/games/morse/morse.c,v 1.3 2005/04/25 16:10:24 liamfoy Exp $ 37 */ 38 39 /* 40 * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM) 41 * <lyndon@orthanc.com> 42 */ 43 44 #include <sys/time.h> 45 46 #include <ctype.h> 47 #include <fcntl.h> 48 #include <langinfo.h> 49 #include <locale.h> 50 #include <signal.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <termios.h> 55 #include <unistd.h> 56 57 #ifdef SPEAKER 58 #include <machine/speaker.h> 59 #endif 60 61 struct morsetab { 62 char inchar; 63 const char *morse; 64 }; 65 66 static const struct morsetab mtab[] = { 67 68 /* letters */ 69 70 {'a', ".-"}, 71 {'b', "-..."}, 72 {'c', "-.-."}, 73 {'d', "-.."}, 74 {'e', "."}, 75 {'f', "..-."}, 76 {'g', "--."}, 77 {'h', "...."}, 78 {'i', ".."}, 79 {'j', ".---"}, 80 {'k', "-.-"}, 81 {'l', ".-.."}, 82 {'m', "--"}, 83 {'n', "-."}, 84 {'o', "---"}, 85 {'p', ".--."}, 86 {'q', "--.-"}, 87 {'r', ".-."}, 88 {'s', "..."}, 89 {'t', "-"}, 90 {'u', "..-"}, 91 {'v', "...-"}, 92 {'w', ".--"}, 93 {'x', "-..-"}, 94 {'y', "-.--"}, 95 {'z', "--.."}, 96 97 /* digits */ 98 99 {'0', "-----"}, 100 {'1', ".----"}, 101 {'2', "..---"}, 102 {'3', "...--"}, 103 {'4', "....-"}, 104 {'5', "....."}, 105 {'6', "-...."}, 106 {'7', "--..."}, 107 {'8', "---.."}, 108 {'9', "----."}, 109 110 /* punctuation */ 111 112 {',', "--..--"}, 113 {'.', ".-.-.-"}, 114 {'?', "..--.."}, 115 {'/', "-..-."}, 116 {'-', "-....-"}, 117 {'=', "-...-"}, /* BT */ 118 {':', "---..."}, 119 {';', "-.-.-."}, 120 {'(', "-.--."}, /* KN */ 121 {')', "-.--.-"}, 122 {'$', "...-..-"}, 123 {'+', ".-.-."}, /* AR */ 124 125 /* prosigns without already assigned values */ 126 127 {'#', ".-..."}, /* AS */ 128 {'@', "...-.-"}, /* SK */ 129 {'*', "...-."}, /* VE */ 130 {'%', "-...-.-"}, /* BK */ 131 132 {'\0', ""} 133 }; 134 135 136 static const struct morsetab iso8859tab[] = { 137 {'�', ".--.-"}, 138 {'�', ".--.-"}, 139 {'�', ".--.-"}, 140 {'�', ".-.-"}, 141 {'�', "-.-.."}, 142 {'�', "..-.."}, 143 {'�', "..-.."}, 144 {'�', "-..-."}, 145 {'�', "---."}, 146 {'�', "..--"}, 147 148 {'\0', ""} 149 }; 150 151 static const struct morsetab koi8rtab[] = { 152 /* 153 * the cyrillic alphabet; you'll need a KOI8R font in order 154 * to see the actual characters 155 */ 156 {'�', ".-"}, /* a */ 157 {'�', "-..."}, /* be */ 158 {'�', ".--"}, /* ve */ 159 {'�', "--."}, /* ge */ 160 {'�', "-.."}, /* de */ 161 {'�', "."}, /* ye */ 162 {'�', "."}, /* yo, the same as ye */ 163 {'�', "...-"}, /* she */ 164 {'�', "--.."}, /* ze */ 165 {'�', ".."}, /* i */ 166 {'�', ".---"}, /* i kratkoye */ 167 {'�', "-.-"}, /* ka */ 168 {'�', ".-.."}, /* el */ 169 {'�', "--"}, /* em */ 170 {'�', "-."}, /* en */ 171 {'�', "---"}, /* o */ 172 {'�', ".--."}, /* pe */ 173 {'�', ".-."}, /* er */ 174 {'�', "..."}, /* es */ 175 {'�', "-"}, /* te */ 176 {'�', "..-"}, /* u */ 177 {'�', "..-."}, /* ef */ 178 {'�', "...."}, /* kha */ 179 {'�', "-.-."}, /* ce */ 180 {'�', "---."}, /* che */ 181 {'�', "----"}, /* sha */ 182 {'�', "--.-"}, /* shcha */ 183 {'�', "-.--"}, /* yi */ 184 {'�', "-..-"}, /* myakhkij znak */ 185 {'�', "..-.."}, /* ae */ 186 {'�', "..--"}, /* yu */ 187 {'�', ".-.-"}, /* ya */ 188 189 {'\0', ""} 190 }; 191 192 void show(const char *), play(const char *), morse(char); 193 void ttyout(const char *); 194 void sighandler(int); 195 196 #define GETOPTOPTS "d:ef:sw:" 197 #define USAGE \ 198 "usage: morse [-s] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n" 199 200 static int pflag, sflag, eflag; 201 static int wpm = 20; /* words per minute */ 202 #define FREQUENCY 600 203 static int freq = FREQUENCY; 204 static char *device; /* for tty-controlled generator */ 205 206 #define DASH_LEN 3 207 #define CHAR_SPACE 3 208 #define WORD_SPACE (7 - CHAR_SPACE - 1) 209 static float dot_clock; 210 int spkr, line; 211 struct termios otty, ntty; 212 int olflags; 213 214 #ifdef SPEAKER 215 tone_t sound; 216 #undef GETOPTOPTS 217 #define GETOPTOPTS "d:ef:psw:" 218 #undef USAGE 219 #define USAGE \ 220 "usage: morse [-s] [-p] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n" 221 #endif 222 223 static const struct morsetab *hightab; 224 225 int 226 main(int argc, char **argv) 227 { 228 int ch, lflags; 229 char *p, *codeset; 230 231 while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1) 232 switch ((char) ch) { 233 case 'd': 234 device = optarg; 235 break; 236 case 'e': 237 eflag = 1; 238 setvbuf(stdout, 0, _IONBF, 0); 239 break; 240 case 'f': 241 freq = atoi(optarg); 242 break; 243 #ifdef SPEAKER 244 case 'p': 245 pflag = 1; 246 break; 247 #endif 248 case 's': 249 sflag = 1; 250 break; 251 case 'w': 252 wpm = atoi(optarg); 253 break; 254 case '?': 255 default: 256 fputs(USAGE, stderr); 257 exit(1); 258 } 259 if ((pflag || device) && sflag) { 260 fputs("morse: only one of -p, -d and -s allowed\n", stderr); 261 exit(1); 262 } 263 if ((pflag || device) && ((wpm < 1) || (wpm > 60))) { 264 fputs("morse: insane speed\n", stderr); 265 exit(1); 266 } 267 if ((pflag || device) && (freq == 0)) 268 freq = FREQUENCY; 269 270 #ifdef SPEAKER 271 if (pflag) { 272 if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) { 273 perror(SPEAKER); 274 exit(1); 275 } 276 } else 277 #endif 278 if (device) { 279 if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) { 280 perror("open tty line"); 281 exit(1); 282 } 283 if (tcgetattr(line, &otty) == -1) { 284 perror("tcgetattr() failed"); 285 exit(1); 286 } 287 ntty = otty; 288 ntty.c_cflag |= CLOCAL; 289 tcsetattr(line, TCSANOW, &ntty); 290 lflags = fcntl(line, F_GETFL); 291 lflags &= ~O_NONBLOCK; 292 fcntl(line, F_SETFL, &lflags); 293 ioctl(line, TIOCMGET, &lflags); 294 lflags &= ~TIOCM_RTS; 295 olflags = lflags; 296 ioctl(line, TIOCMSET, &lflags); 297 (void)signal(SIGHUP, sighandler); 298 (void)signal(SIGINT, sighandler); 299 (void)signal(SIGQUIT, sighandler); 300 (void)signal(SIGTERM, sighandler); 301 } 302 if (pflag || device) { 303 dot_clock = wpm / 2.4; /* dots/sec */ 304 dot_clock = 1 / dot_clock; /* duration of a dot */ 305 dot_clock = dot_clock / 2; /* dot_clock runs at twice */ 306 /* the dot rate */ 307 dot_clock = dot_clock * 100; /* scale for ioctl */ 308 } 309 310 argc -= optind; 311 argv += optind; 312 313 if (setlocale(LC_CTYPE, "") != NULL && 314 *(codeset = nl_langinfo(CODESET)) != '\0') { 315 if (strcmp(codeset, "KOI8-R") == 0) 316 hightab = koi8rtab; 317 else if (strcmp(codeset, "ISO8859-1") == 0 || 318 strcmp(codeset, "ISO8859-15") == 0) 319 hightab = iso8859tab; 320 } 321 322 if (*argv) { 323 do { 324 for (p = *argv; *p; ++p) { 325 if (eflag) 326 putchar(*p); 327 morse(*p); 328 } 329 if (eflag) 330 putchar(' '); 331 morse(' '); 332 } while (*++argv); 333 } else { 334 while ((ch = getchar()) != EOF) { 335 if (eflag) 336 putchar(ch); 337 morse(ch); 338 } 339 } 340 if (device) 341 tcsetattr(line, TCSANOW, &otty); 342 exit(0); 343 } 344 345 void 346 morse(char c) 347 { 348 const struct morsetab *m; 349 350 if (isalpha((unsigned char)c)) 351 c = tolower((unsigned char)c); 352 if ((c == '\r') || (c == '\n')) 353 c = ' '; 354 if (c == ' ') { 355 if (pflag) { 356 play(" "); 357 return; 358 } else if (device) { 359 ttyout(" "); 360 return; 361 } else { 362 show(""); 363 return; 364 } 365 } 366 for (m = ((unsigned char)c < 0x80? mtab: hightab); 367 m != NULL && m->inchar != '\0'; 368 m++) { 369 if (m->inchar == c) { 370 if (pflag) { 371 play(m->morse); 372 } else if (device) { 373 ttyout(m->morse); 374 } else 375 show(m->morse); 376 } 377 } 378 } 379 380 void 381 show(const char *s) 382 { 383 if (sflag) 384 printf(" %s", s); 385 else 386 for (; *s; ++s) 387 printf(" %s", *s == '.' ? "dit" : "dah"); 388 printf("\n"); 389 } 390 391 void 392 play(const char *s) 393 { 394 #ifdef SPEAKER 395 const char *c; 396 397 for (c = s; *c != '\0'; c++) { 398 switch (*c) { 399 case '.': 400 sound.frequency = freq; 401 sound.duration = dot_clock; 402 break; 403 case '-': 404 sound.frequency = freq; 405 sound.duration = dot_clock * DASH_LEN; 406 break; 407 case ' ': 408 sound.frequency = 0; 409 sound.duration = dot_clock * WORD_SPACE; 410 break; 411 default: 412 sound.duration = 0; 413 } 414 if (sound.duration) { 415 if (ioctl(spkr, SPKRTONE, &sound) == -1) { 416 perror("ioctl play"); 417 exit(1); 418 } 419 } 420 sound.frequency = 0; 421 sound.duration = dot_clock; 422 if (ioctl(spkr, SPKRTONE, &sound) == -1) { 423 perror("ioctl rest"); 424 exit(1); 425 } 426 } 427 sound.frequency = 0; 428 sound.duration = dot_clock * CHAR_SPACE; 429 ioctl(spkr, SPKRTONE, &sound); 430 #endif 431 } 432 433 void 434 ttyout(const char *s) 435 { 436 const char *c; 437 int duration, on, lflags; 438 439 for (c = s; *c != '\0'; c++) { 440 switch (*c) { 441 case '.': 442 on = 1; 443 duration = dot_clock; 444 break; 445 case '-': 446 on = 1; 447 duration = dot_clock * DASH_LEN; 448 break; 449 case ' ': 450 on = 0; 451 duration = dot_clock * WORD_SPACE; 452 break; 453 default: 454 on = 0; 455 duration = 0; 456 } 457 if (on) { 458 ioctl(line, TIOCMGET, &lflags); 459 lflags |= TIOCM_RTS; 460 ioctl(line, TIOCMSET, &lflags); 461 } 462 duration *= 10000; 463 if (duration) 464 usleep(duration); 465 ioctl(line, TIOCMGET, &lflags); 466 lflags &= ~TIOCM_RTS; 467 ioctl(line, TIOCMSET, &lflags); 468 duration = dot_clock * 10000; 469 usleep(duration); 470 } 471 duration = dot_clock * CHAR_SPACE * 10000; 472 usleep(duration); 473 } 474 475 void 476 sighandler(int signo) 477 { 478 479 ioctl(line, TIOCMSET, &olflags); 480 tcsetattr(line, TCSANOW, &otty); 481 482 signal(signo, SIG_DFL); 483 (void)kill(getpid(), signo); 484 } 485