2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * Taught to send *real* morse by Lyndon Nerenberg (VE6BBM)
36 static const char copyright[] =
37 "@(#) Copyright (c) 1988, 1993\n\
38 The Regents of the University of California. All rights reserved.\n";
43 static char sccsid[] = "@(#)morse.c 8.1 (Berkeley) 5/31/93";
45 static const char rcsid[] =
62 /* Always use the speaker, let the open fail if -p is selected */
63 #define SPEAKER "/dev/speaker"
66 #include <dev/speaker/speaker.h>
74 static const struct morsetab mtab[] = {
127 {'=', "-...-"}, /* BT */
130 {'(', "-.--."}, /* KN */
133 {'+', ".-.-."}, /* AR */
134 {'@', ".--.-."}, /* AC */
136 /* prosigns without already assigned values */
138 {'#', ".-..."}, /* AS */
139 {'&', "...-.-"}, /* SK */
140 {'*', "...-."}, /* VE */
141 {'%', "-...-.-"}, /* BK */
147 static const struct morsetab iso8859_1tab[] = {
162 static const struct morsetab iso8859_7tab[] = {
164 * The Greek alphabet; you'll need an ISO8859-7 font in order
165 * to see the actual characters.
166 * This table does not implement:
167 * - the special sequences for the seven diphthongs,
168 * - the punctuation differences.
169 * Implementing these features would introduce too many
170 * special-cases in the program's main loop.
171 * The diphthong sequences are:
174 * epsilon upsilon ---.
177 * omicron upsilon ..-
179 * The different punctuation symbols are:
183 {'á', ".-"}, /* alpha */
184 {'Ü', ".-"}, /* alpha with acute */
185 {'â', "-..."}, /* beta */
186 {'ã', "--."}, /* gamma */
187 {'ä', "-.."}, /* delta */
188 {'å', "."}, /* epsilon */
189 {'Ý', "."}, /* epsilon with acute */
190 {'æ', "--.."}, /* zeta */
191 {'ç', "...."}, /* eta */
192 {'Þ', "...."}, /* eta with acute */
193 {'è', "-.-."}, /* theta */
194 {'é', ".."}, /* iota */
195 {'ß', ".."}, /* iota with acute */
196 {'ú', ".."}, /* iota with diaeresis */
197 {'À', ".."}, /* iota with acute and diaeresis */
198 {'ê', "-.-"}, /* kappa */
199 {'ë', ".-.."}, /* lambda */
200 {'ì', "--"}, /* mu */
201 {'í', "-."}, /* nu */
202 {'î', "-..-"}, /* xi */
203 {'ï', "---"}, /* omicron */
204 {'ü', "---"}, /* omicron with acute */
205 {'ð', ".--."}, /* pi */
206 {'ñ', ".-."}, /* rho */
207 {'ó', "..."}, /* sigma */
208 {'ò', "..."}, /* final sigma */
209 {'ô', "-"}, /* tau */
210 {'õ', "-.--"}, /* upsilon */
211 {'ý', "-.--"}, /* upsilon with acute */
212 {'û', "-.--"}, /* upsilon and diaeresis */
213 {'à', "-.--"}, /* upsilon with acute and diaeresis */
214 {'ö', "..-."}, /* phi */
215 {'÷', "----"}, /* chi */
216 {'ø', "--.-"}, /* psi */
217 {'ù', ".--"}, /* omega */
218 {'þ', ".--"}, /* omega with acute */
223 static const struct morsetab koi8rtab[] = {
225 * The Cyrillic alphabet; you'll need a KOI8-R font in order
226 * to see the actual characters
229 {'Â', "-..."}, /* be */
230 {'×', ".--"}, /* ve */
231 {'Ç', "--."}, /* ge */
232 {'Ä', "-.."}, /* de */
234 {'£', "."}, /* yo, the same as ye */
235 {'Ö', "...-"}, /* she */
236 {'Ú', "--.."}, /* ze */
238 {'Ê', ".---"}, /* i kratkoye */
239 {'Ë', "-.-"}, /* ka */
240 {'Ì', ".-.."}, /* el */
241 {'Í', "--"}, /* em */
242 {'Î', "-."}, /* en */
243 {'Ï', "---"}, /* o */
244 {'Ð', ".--."}, /* pe */
245 {'Ò', ".-."}, /* er */
246 {'Ó', "..."}, /* es */
248 {'Õ', "..-"}, /* u */
249 {'Æ', "..-."}, /* ef */
250 {'È', "...."}, /* kha */
251 {'Ã', "-.-."}, /* ce */
252 {'Þ', "---."}, /* che */
253 {'Û', "----"}, /* sha */
254 {'Ý', "--.-"}, /* shcha */
255 {'Ù', "-.--"}, /* yi */
256 {'Ø', "-..-"}, /* myakhkij znak */
257 {'Ü', "..-.."}, /* ae */
258 {'À', "..--"}, /* yu */
259 {'Ñ', ".-.-"}, /* ya */
264 static void show(const char *), play(const char *), morse(char);
265 static void ttyout(const char *);
266 static void sighandler(int);
268 #define GETOPTOPTS "c:d:ef:lsw:"
270 "usage: morse [-els] [-d device] [-w speed] [-c speed] [-f frequency] [string ...]\n"
272 static int pflag, lflag, sflag, eflag;
273 static int wpm = 20; /* effective words per minute */
274 static int cpm; /* effective words per minute between
276 #define FREQUENCY 600
277 static int freq = FREQUENCY;
278 static char *device; /* for tty-controlled generator */
282 #define WORD_SPACE (7 - CHAR_SPACE - 1)
283 static float dot_clock;
284 static float cdot_clock;
285 static int spkr, line;
286 static struct termios otty, ntty;
292 #define GETOPTOPTS "c:d:ef:lpsw:"
295 "usage: morse [-elps] [-d device] [-w speed] [-c speed] [-f frequency] [string ...]\n"
298 static const struct morsetab *hightab;
301 main(int argc, char **argv)
306 while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1)
316 setvbuf(stdout, 0, _IONBF, 0);
337 fputs(USAGE, stderr);
340 if (sflag && lflag) {
341 fputs("morse: only one of -l and -s allowed\n", stderr);
344 if ((pflag || device) && (sflag || lflag)) {
345 fputs("morse: only one of -p, -d and -l, -s allowed\n", stderr);
350 if ((pflag || device) && ((wpm < 1) || (wpm > 60) || (cpm < 1) || (cpm > 60))) {
351 fputs("morse: insane speed\n", stderr);
354 if ((pflag || device) && (freq == 0))
359 if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
366 if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) {
367 perror("open tty line");
370 if (tcgetattr(line, &otty) == -1) {
371 perror("tcgetattr() failed");
375 ntty.c_cflag |= CLOCAL;
376 tcsetattr(line, TCSANOW, &ntty);
377 lflags = fcntl(line, F_GETFL);
378 lflags &= ~O_NONBLOCK;
379 fcntl(line, F_SETFL, &lflags);
380 ioctl(line, TIOCMGET, &lflags);
381 lflags &= ~TIOCM_RTS;
383 ioctl(line, TIOCMSET, &lflags);
384 (void)signal(SIGHUP, sighandler);
385 (void)signal(SIGINT, sighandler);
386 (void)signal(SIGQUIT, sighandler);
387 (void)signal(SIGTERM, sighandler);
389 if (pflag || device) {
390 dot_clock = wpm / 2.4; /* dots/sec */
391 dot_clock = 1 / dot_clock; /* duration of a dot */
392 dot_clock = dot_clock / 2; /* dot_clock runs at twice */
394 dot_clock = dot_clock * 100; /* scale for ioctl */
396 cdot_clock = cpm / 2.4; /* dots/sec */
397 cdot_clock = 1 / cdot_clock; /* duration of a dot */
398 cdot_clock = cdot_clock / 2; /* dot_clock runs at twice */
400 cdot_clock = cdot_clock * 100; /* scale for ioctl */
406 if (setlocale(LC_CTYPE, "") != NULL &&
407 *(codeset = nl_langinfo(CODESET)) != '\0') {
408 if (strcmp(codeset, "KOI8-R") == 0)
410 else if (strcmp(codeset, "ISO8859-1") == 0 ||
411 strcmp(codeset, "ISO8859-15") == 0)
412 hightab = iso8859_1tab;
413 else if (strcmp(codeset, "ISO8859-7") == 0)
414 hightab = iso8859_7tab;
421 for (p = *argv; *p; ++p) {
431 while ((ch = getchar()) != EOF) {
438 tcsetattr(line, TCSANOW, &otty);
445 const struct morsetab *m;
447 if (isalpha((unsigned char)c))
448 c = tolower((unsigned char)c);
449 if ((c == '\r') || (c == '\n'))
462 for (m = ((unsigned char)c < 0x80? mtab: hightab);
463 m != NULL && m->inchar != '\0';
465 if (m->inchar == c) {
485 printf(" %s", *s == '.' ? *(s + 1) == '\0' ? "dit" :
497 for (c = s; *c != '\0'; c++) {
500 sound.frequency = freq;
501 sound.duration = dot_clock;
504 sound.frequency = freq;
505 sound.duration = dot_clock * DASH_LEN;
509 sound.duration = cdot_clock * WORD_SPACE;
514 if (sound.duration) {
515 if (ioctl(spkr, SPKRTONE, &sound) == -1) {
516 perror("ioctl play");
521 sound.duration = dot_clock;
522 if (ioctl(spkr, SPKRTONE, &sound) == -1) {
523 perror("ioctl rest");
528 sound.duration = cdot_clock * CHAR_SPACE;
529 ioctl(spkr, SPKRTONE, &sound);
534 ttyout(const char *s)
537 int duration, on, lflags;
539 for (c = s; *c != '\0'; c++) {
543 duration = dot_clock;
547 duration = dot_clock * DASH_LEN;
551 duration = cdot_clock * WORD_SPACE;
558 ioctl(line, TIOCMGET, &lflags);
560 ioctl(line, TIOCMSET, &lflags);
565 ioctl(line, TIOCMGET, &lflags);
566 lflags &= ~TIOCM_RTS;
567 ioctl(line, TIOCMSET, &lflags);
568 duration = dot_clock * 10000;
571 duration = cdot_clock * CHAR_SPACE * 10000;
576 sighandler(int signo)
579 ioctl(line, TIOCMSET, &olflags);
580 tcsetattr(line, TCSANOW, &otty);
582 signal(signo, SIG_DFL);
583 (void)kill(getpid(), signo);