Add an eleventh-hour gimick... But since it's only in `games' and
Jordan OK'ed it, i think it's a nice one for those who need it. I once mentioned in Usenet that i've hacked morse(6) so it can control an external device like a tone generator or even a ham radio transceiver, so you could actually use that `game' for really transmitting morse code through the air. A couple of people then bugged be to send them my hack (which it was by that time). So i've now finally found some hours to clean it up (like freaking out with the transmitter no longer keyed in case someone ^c's out of the program...), and to write the man page addition. While i was at it, i also cleaned up some minor nits in Lyndon's /dev/speaker code, mainly #ifdef related stuff like handling getopt() if SPEAKER is not defined etc. enjoy & 73 Approved by: jkh, the restless...
This commit is contained in:
parent
2217c725f9
commit
0206896d32
@ -47,6 +47,8 @@
|
||||
.Op Ar string ...
|
||||
.Nm morse
|
||||
.Op Fl p
|
||||
.Op Fl d Ar device
|
||||
.Op Fl e
|
||||
.Op Fl w Ar speed
|
||||
.Op Fl f Ar frequency
|
||||
.Op Fl s
|
||||
@ -61,28 +63,44 @@ read the given input and reformat it in the form of punched cards,
|
||||
paper tape or morse code respectively.
|
||||
Acceptable input are command line arguments or the standard input.
|
||||
.Pp
|
||||
Available option:
|
||||
Available options for program
|
||||
.Nm morse :
|
||||
.Bl -tag -width flag
|
||||
.It Fl s
|
||||
The
|
||||
.Fl s
|
||||
option for morse produces dots and dashes rather than words.
|
||||
option produces dots and dashes rather than words.
|
||||
.It Fl p
|
||||
Send morse the real way. This only works if your system has sound
|
||||
support and if the program understands your audio hardware.
|
||||
Send morse the real way. This only works if your system has
|
||||
.Xr speaker 4
|
||||
support.
|
||||
.It Fl w Ar speed
|
||||
Set the sending speed in words per minute. If not specified the default
|
||||
speed of 20 WPM is used.
|
||||
.It Fl f Ar frequency
|
||||
Set the sidetone frequency to something other than the default 600 Hz.
|
||||
.It Fl d Ar device
|
||||
Similar to
|
||||
.Fl p ,
|
||||
but use the RTS line of
|
||||
.Ar device
|
||||
.Pq which must by a tty device
|
||||
in order to emit the morse code.
|
||||
.It Fl e
|
||||
echo each character before it is sent, used together with either
|
||||
.Fl p
|
||||
or
|
||||
.Fl d .
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fl w
|
||||
and
|
||||
.Fl f
|
||||
flags only work in conjunction with the
|
||||
flags only work in conjunction with either the
|
||||
.Fl p
|
||||
or the
|
||||
.Fl d
|
||||
flag.
|
||||
.Pp
|
||||
Not all prosigns have corresponding characters. Use
|
||||
@ -110,6 +128,19 @@ and
|
||||
.Ql +
|
||||
for
|
||||
.Em AR .
|
||||
.Pp
|
||||
Using flag
|
||||
.Fl d Ar device
|
||||
it is possible to key an external device, like a sidetone generator with
|
||||
a headset for training purposes, or even your ham radio transceiver. For
|
||||
the latter, simply connect an NPN transistor to the serial port
|
||||
.Ar device ,
|
||||
emitter connected to ground, base connected through a resistor
|
||||
(few kiloohms) to RTS, collector to the key line of your transceiver
|
||||
(assuming the transceiver has a positive key supply voltage and is keyed
|
||||
by grounding the key input line). A capacitor (some nanofarads) between
|
||||
base and ground is advisable to keep stray RF away, and to supress the
|
||||
minor glitch that is generated during program startup.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /dev/speaker -compact
|
||||
.It Pa /dev/speaker
|
||||
@ -131,10 +162,17 @@ Cyrillic characters. In all other cases, they are being interpreted
|
||||
as belonging to the
|
||||
.Ql ISO_8859-1
|
||||
character set.
|
||||
.Sh SEE ALSO
|
||||
.Xr speaker 4
|
||||
.Sh HISTORY
|
||||
Sound support for
|
||||
.Nm morse
|
||||
added by Lyndon Nerenberg (VE7TCP/VE6BBM) <lyndon@orthanc.com>.
|
||||
.Pp
|
||||
Ability to key an external device added by
|
||||
.ie t J\(:org Wunsch
|
||||
.el Joerg Wunsch
|
||||
(DL8DTL).
|
||||
.Sh BUGS
|
||||
Does only understand a few European characters (namely German and
|
||||
French), but neither Asian ones, or the continental landline code.
|
||||
|
@ -50,16 +50,20 @@ static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef SPEAKER
|
||||
#include <machine/speaker.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
struct morsetab {
|
||||
@ -194,19 +198,34 @@ static const struct morsetab koi8rtab[] = {
|
||||
};
|
||||
|
||||
void show(const char *), play(const char *), morse(char);
|
||||
void ttyout(const char *);
|
||||
void sighandler(int);
|
||||
|
||||
static int pflag, sflag;
|
||||
#define GETOPTOPTS "d:ef:sw:"
|
||||
#define USAGE \
|
||||
"usage: morse [-s] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n"
|
||||
|
||||
static int pflag, sflag, eflag;
|
||||
static int wpm = 20; /* words per minute */
|
||||
#define FREQUENCY 600
|
||||
static int freq = FREQUENCY;
|
||||
static char *device; /* for tty-controlled generator */
|
||||
|
||||
#ifdef SPEAKER
|
||||
#define DASH_LEN 3
|
||||
#define CHAR_SPACE 3
|
||||
#define WORD_SPACE (7 - CHAR_SPACE - 1)
|
||||
static float dot_clock;
|
||||
int spkr;
|
||||
int spkr, line;
|
||||
struct termios otty, ntty;
|
||||
int olflags;
|
||||
|
||||
#ifdef SPEAKER
|
||||
tone_t sound;
|
||||
#undef GETOPTOPTS
|
||||
#define GETOPTOPTS "d:ef:psw:"
|
||||
#undef USAGE
|
||||
#define USAGE \
|
||||
"usage: morse [-s] [-p] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n"
|
||||
#endif
|
||||
|
||||
static const struct morsetab *hightab = iso8859tab;
|
||||
@ -214,17 +233,26 @@ static const struct morsetab *hightab = iso8859tab;
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
int ch, lflags;
|
||||
char *p;
|
||||
|
||||
while ((ch = getopt(argc, argv, "spw:f:")) != -1)
|
||||
while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1)
|
||||
switch ((char) ch) {
|
||||
case 'd':
|
||||
device = optarg;
|
||||
break;
|
||||
case 'e':
|
||||
eflag = 1;
|
||||
setvbuf(stdout, 0, _IONBF, 0);
|
||||
break;
|
||||
case 'f':
|
||||
freq = atoi(optarg);
|
||||
break;
|
||||
#ifdef SPEAKER
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
break;
|
||||
#endif
|
||||
case 's':
|
||||
sflag = 1;
|
||||
break;
|
||||
@ -233,18 +261,18 @@ main(int argc, char **argv)
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
fputs("usage: morse [-s] [-p] [-w speed] [-f frequency] [string ...]\n", stderr);
|
||||
fputs(USAGE, stderr);
|
||||
exit(1);
|
||||
}
|
||||
if (pflag && sflag) {
|
||||
fputs("morse: only one of -p and -s allowed\n", stderr);
|
||||
if ((pflag || device) && sflag) {
|
||||
fputs("morse: only one of -p, -d and -s allowed\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
if (pflag && ((wpm < 1) || (wpm > 60))) {
|
||||
if ((pflag || device) && ((wpm < 1) || (wpm > 60))) {
|
||||
fputs("morse: insane speed\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
if (pflag && (freq == 0))
|
||||
if ((pflag || device) && (freq == 0))
|
||||
freq = FREQUENCY;
|
||||
|
||||
#ifdef SPEAKER
|
||||
@ -253,13 +281,40 @@ main(int argc, char **argv)
|
||||
perror(SPEAKER);
|
||||
exit(1);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (device) {
|
||||
if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) {
|
||||
perror("open tty line");
|
||||
exit(1);
|
||||
}
|
||||
if (tcgetattr(line, &otty) == -1) {
|
||||
perror("tcgetattr() failed");
|
||||
exit(1);
|
||||
}
|
||||
ntty = otty;
|
||||
ntty.c_cflag |= CLOCAL;
|
||||
tcsetattr(line, TCSANOW, &ntty);
|
||||
lflags = fcntl(line, F_GETFL);
|
||||
lflags &= ~O_NONBLOCK;
|
||||
fcntl(line, F_SETFL, &lflags);
|
||||
ioctl(line, TIOCMGET, &lflags);
|
||||
lflags &= ~TIOCM_RTS;
|
||||
olflags = lflags;
|
||||
ioctl(line, TIOCMSET, &lflags);
|
||||
(void)signal(SIGHUP, sighandler);
|
||||
(void)signal(SIGINT, sighandler);
|
||||
(void)signal(SIGQUIT, sighandler);
|
||||
(void)signal(SIGTERM, sighandler);
|
||||
}
|
||||
if (pflag || device) {
|
||||
dot_clock = wpm / 2.4; /* dots/sec */
|
||||
dot_clock = 1 / dot_clock; /* duration of a dot */
|
||||
dot_clock = dot_clock / 2; /* dot_clock runs at twice */
|
||||
/* the dot rate */
|
||||
dot_clock = dot_clock * 100; /* scale for ioctl */
|
||||
}
|
||||
#endif
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
@ -275,14 +330,23 @@ main(int argc, char **argv)
|
||||
if (*argv) {
|
||||
do {
|
||||
for (p = *argv; *p; ++p) {
|
||||
if (eflag)
|
||||
putchar(*p);
|
||||
morse(*p);
|
||||
}
|
||||
if (eflag)
|
||||
putchar(' ');
|
||||
morse(' ');
|
||||
} while (*++argv);
|
||||
} else {
|
||||
while ((ch = getchar()) != EOF)
|
||||
while ((ch = getchar()) != EOF) {
|
||||
if (eflag)
|
||||
putchar(ch);
|
||||
morse(ch);
|
||||
}
|
||||
}
|
||||
if (device)
|
||||
tcsetattr(line, TCSANOW, &otty);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@ -299,6 +363,9 @@ morse(char c)
|
||||
if (pflag) {
|
||||
play(" ");
|
||||
return;
|
||||
} else if (device) {
|
||||
ttyout(" ");
|
||||
return;
|
||||
} else {
|
||||
show("");
|
||||
return;
|
||||
@ -310,6 +377,8 @@ morse(char c)
|
||||
if (m->inchar == c) {
|
||||
if (pflag) {
|
||||
play(m->morse);
|
||||
} else if (device) {
|
||||
ttyout(m->morse);
|
||||
} else
|
||||
show(m->morse);
|
||||
}
|
||||
@ -368,3 +437,56 @@ play(const char *s)
|
||||
ioctl(spkr, SPKRTONE, &sound);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ttyout(const char *s)
|
||||
{
|
||||
const char *c;
|
||||
int duration, on, lflags;
|
||||
|
||||
for (c = s; *c != '\0'; c++) {
|
||||
switch (*c) {
|
||||
case '.':
|
||||
on = 1;
|
||||
duration = dot_clock;
|
||||
break;
|
||||
case '-':
|
||||
on = 1;
|
||||
duration = dot_clock * DASH_LEN;
|
||||
break;
|
||||
case ' ':
|
||||
on = 0;
|
||||
duration = dot_clock * WORD_SPACE;
|
||||
break;
|
||||
default:
|
||||
on = 0;
|
||||
duration = 0;
|
||||
}
|
||||
if (on) {
|
||||
ioctl(line, TIOCMGET, &lflags);
|
||||
lflags |= TIOCM_RTS;
|
||||
ioctl(line, TIOCMSET, &lflags);
|
||||
}
|
||||
duration *= 10000;
|
||||
if (duration)
|
||||
usleep(duration);
|
||||
ioctl(line, TIOCMGET, &lflags);
|
||||
lflags &= ~TIOCM_RTS;
|
||||
ioctl(line, TIOCMSET, &lflags);
|
||||
duration = dot_clock * 10000;
|
||||
usleep(duration);
|
||||
}
|
||||
duration = dot_clock * CHAR_SPACE * 10000;
|
||||
usleep(duration);
|
||||
}
|
||||
|
||||
void
|
||||
sighandler(int signo)
|
||||
{
|
||||
|
||||
ioctl(line, TIOCMSET, &olflags);
|
||||
tcsetattr(line, TCSANOW, &otty);
|
||||
|
||||
signal(signo, SIG_DFL);
|
||||
(void)kill(getpid(), signo);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user