1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
SLOWBAUD(1) Urchlay's Useless Stuff SLOWBAUD(1)
NAME
slowbaud - simulate a low bitrate serial connection
SYNOPSIS
slowbaud [<bits-per-sec>] [<file> ...]
slowbaud [<bits-per-sec>] -c [<command> [<arg> ...]]
slowbaud [<bits-per-sec>] -e <string> [<string> ...]
slowbaud [<bits-per-sec>] -b [<bytes>]
DESCRIPTION
slowbaud by default acts as a filter, or like the cat(1) command. It reads
files or its standard input, and writes the contents unmodified to standard
output... but slowly, at the given bits-per-second rate. Input and output are
unbuffered.
slowbaud can also act like echo(1) (the -e option), or run an interactive com‐
mand in a pseudo-tty (the -c option).
The <bits-per-sec> argument is optional. If it's not given, the bit rate will
be set from SLOWBAUD_BPS in the environment, or a built-in default of 2400 if
that's not set.
OPTIONS
bits-per-sec
The bit ("baud") rate to simulate. Range is 1 to 500000. This must be
the first argument. slowbaud assumes that if the first argument is a
number, it's the bit rate. If you're trying to pass a filename that
consists only of digits, give -- as the first argument, or use e.g.
./filename.
-e Echo mode. Prints all further arguments as strings to stdout, separated
by a single space, at the given bit rate. Does not support back‐
slash-escapes, or any of the options of the regular echo command. At
least one argument is required after -e.
-c Command mode. Next argument (if present) is the command to run, any
remaining arguments become arguments to the command. With no arguments
after -c, a shell is spawned. This creates a pseudo-tty, so the com‐
mand can be interactive.
-b Benchmark mode. Prints <bytes> (or 4096, if no <bytes> given) bytes of
zeroes to /dev/null. Mostly useful for development and troubleshooting.
-h, -? Show built-in help message and exit.
ENVIRONMENT
SLOWBAUD_BPS
Can be used to set the bit rate, when no <bits-per-sec> argument is
used.
SLOWBAUD_DEBUG
Set this (to any value) in the environment to see verbose debug output
on stderr, including timing accuracy stats.
SHELL Standard *nix environment variable, used to determine what shell to run
when -c is given with no <command>. If unset, /bin/sh is used.
EXIT STATUS
Without -c or -e, 0 for success, non-zero on any error such as nonexis‐
tent/unreadable files. slowbaud exits immediately on such errors (this is
unlike cat(1)).
With -e, exit status is 0, unless there were no arguments to echo.
With -c, exit status is that of the child process, or 127 if the child process
couldn't be spawned (e.g. command not found). Of course, the child process
could also exit with status 127...
With -b, exit status is 0, unless something catastrophic happened (e.g. unable
to open /dev/null for writing).
NOTES
The timing inaccuracy will almost always result in the bitrate being slightly
too slow.
We can't really insert a delay between the bits of a byte, since I/O is done
with byte granularity. For calculation purposes, <bits-per-sec> is divided by
10 to get bytes per second. This simulates "8-N-1": one start bit, 8 data
bits, no parity, and 1 stop bit (total of 10 bits per byte).
The timing code works by calculating how long to sleep after each character
(in microseconds), but actually sleeping slightly less than that, then
busy-waiting until the rest of the interval expires. At slower bitrates, this
works well, and the CPU overhead is barely noticeable (at least on reasonably
fast modern systems).
Timing accuracy depends on your OS, kernel config (HZ and/or NO_HZ on Linux),
and system load. Also on the amount of data, since the timing loop is
self-regulating (the first few bytes will have less accurate timing than later
ones). No "fancy" techniques like realtime scheduling or hardware event timers
are used. At bitrates up to 115200, on an unloaded Linux system, the timing
should be at least 99.9% accurate. At higher bitrates, accuracy will decrease.
Timing is more accurate on Linux than OSX. It's done with getitimer() and sig‐
wait(). This works out to be slightly more accurate than using usleep() on
both Linux and OSX. It would be possible to use the realtime timer_create()
and clock_gettime() API on Linux, for possibly even better accuracy, but OSX
doesn't have these (and I want to be portable). On an unloaded OSX system, the
accuracy gets steadily worse as you go above 57600bps. There's also more CPU
overhead on OSX.
If this were a truly useful application, it would be worth trying to increase
accuracy further, with realtime process scheduling. I didn't do this because
slowbaud is just a toy, and because the RT stuff tends to be unportable and
require elevated privileges (root, or something like setrtlimit or extended
filesystem attributes to manage capabilities).
About the name... I'm aware that "baud" is not synonymous with bps. I just
think "slowbaud" sounds better than "slowbps", as a name. Anyway the stty com‐
mand on both Linux and OSX misuses the term ("speed 38400 baud"), as well as
the man page for termios(3), so I'm in good company.
BUGS
With -c, signals aren't handled gracefully. Window size changes (SIGWINCH)
don't get propagated to the child process, and pressing ^C doesn't interrupt
the process until all pending output is processed.
COPYRIGHT
slowbaud is copyright 2021, B. Watson <yalhcru@gmail.com>. Released under the
WTFPL. See http://www.wtfpl.net/txt/copying/ for details.
0.0.1 2021-07-23 SLOWBAUD(1)
|