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
|
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> ...]]
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. Output is unbuffered.
With the -c option, it creates a pseudo-tty and runs the given command in it (or an
interactive shell, if no command is given).
The <bits-per-sec> argument supports a range of 1 to 500000. Timing accuracy depends
on your OS, kernel config (HZ and/or NO_HZ on Linux), and system load. No "fancy"
techniques like realtime scheduling or hardware event timers are used. At bitrates up
to 57600, on a typical unloaded Linux system, the timing should be around 99.7% accu‐
rate.
ENVIRONMENT
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, 0 for success, non-zero on any error such as nonexistent/unreadable files.
slowbaud exits immediately on such errors (this is unlike cat(1)).
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...
NOTES
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).
The timing error will almost always result in the bitrate being slightly too slow at
lower bitrates and slightly too fast at higher ones.
Timing is more accurate on Linux than OSX. It's done with getitimer() and sigwait().
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).
If this were a truly useful application, it would be worth trying to decrease latency
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 capa‐
bilities).
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 command on Linux
misuses the term ("speed 38400 baud"), 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. Yet.
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-21 SLOWBAUD(1)
|