BOOTTERM(1)
π BOOTTERM(1) β the User Commands page, bestie edition π
okay so β¨ vibe check β¨ β you just landed on the User Commands manual page, and the star of the show is BootTerm, aka bt. She's a terminal, she's simple, she's reliable, and she's about to make your SBC life so much easier. Buckle up. π
π NAME π
BootTerm β simple terminal to ease connections with SBCs
πΈ SYNOPSIS πΈ
bt [options] [/dev/ttyXXX | port#]
that's it. that's the whole summoning ritual. πͺ
π¦ DESCRIPTION π¦
BootTerm is a simple, reliable and powerful terminal designed to ease connection to ephemeral serial ports as found on various SBCs, and typically USB-based ones. Like, it's literally built for the exact chaos you're in. π
- automatic port detection (uses the most recently registered one by default) π
- enumeration of available ports with detected drivers and descriptions π
- wait for a specific, a new, or any port to appear (convenient with USB ports) β³
- support for non-standard baud rates (e.g.
74880bauds for ESP8266) π - can send a Break sequence and toggling RTS/DTR for various reset sequences, even on startup π
- fixed/timed captures to files (may be enabled at run time) π
- optionally time-stamped captures (relative/absolute dates) π°οΈ
- reliable with proper error handling π‘οΈ
- single binary without annoying dependencies, builds out of the box π¦
- supports stdin/stdout to inject/download data π
- configurable escape character and visible character ranges ποΈ
likeβ¦ she does everything. main character energy fr fr. π
β¨ OPTIONS β¨
-hβ display this help-qβ quiet mode: do not report events π€«-pβ only print selected port name and quit-lβ list detected serial ports and quit π-aβ wait for a port to be available (BT_SCAN_WAIT_ANY)-nβ wait for a new port to be registered (BT_SCAN_WAIT_NEW)-m <min>β specify lowest printable character (default:0)-M <max>β specify highest printable character (default:255)-b <baud>β specify baud rate (BT_PORT_BAUD_RATE; default:115200;0=current)-c {none|fixed|timed}β enable capture to file (BT_CAPTURE_MODE)-t {none|abs|init|line}β enable timestamps in captures (BT_TIMESTAMP_MODE)-Tβ enable timestamps in terminal (see-tfor formats)-e <escape>β escape character or ASCII code (default:29=Ctrl-])-f <fmt>β capture file name (default:'bootterm-%Y%m%d-%H%M%S.log')-Vβ show version and license-Bβ send a break sequence before starting the terminal-Nβ do not launch the terminal, just quit-L <mode>β new line mode:0=CRLF,1=LF only,2=CR only (BT_PORT_CRLF)
Ports are sorted in reverse registration order so that port 0 is the most recently added one. A number may be set instead of the port. With no name nor number, last port is used. Use '?' or 'help' in baud rate to list them all. Comma-delimited lists of ports to exclude/include/restrict may be passed in BT_SCAN_EXCLUDE_PORTS, BT_SCAN_INCLUDE_PORTS, and BT_SCAN_RESTRICT_PORTS. BT_SCAN_EXCLUDE_DRIVERS ignores ports matching these drivers. π§ β¨
Built with support for custom baud rates (TCGETS2). Copyright Β© 2020-2021 Willy Tarreau<w@1wt.eu>This is free software: you are encouraged to improve and redistribute it. There is no warranty of any kind, see the source for license details.
π EXAMPLES π
π Most common usage π
By default, bt connects to the last registered serial port, which usually is the most recently connected USB adapter. A list of currently available ports is obtained by bt -l:
$ bt -l
port | age (sec) | device | driver | description
------+------------+------------+------------------+----------------------
0 | 524847 | ttyAMA0 | uart-pl011 |
1 | 524847 | ttyUSB0 | ftdi_sio | TTL232R-3V3
2 | 1320 | ttyUSB1 | ch341-uart |
* 3 | 206 | ttyUSB2 | cp210x | CP2102 USB to UART Bridge Controller
In the example above, ttyUSB2 will be used when no option is specified (which is indicated by the star in front of the port number). Otherwise, running bt ttyUSB2, bt /dev/ttyS0, or anything else will also do what is expected. The help is shown with bt -h.
Once connected, the default escape character is the same as telnet: Ctrl-] (Control and right-square-bracket). After the escape character, a single character is expected to issue an internal command. Quitting is achieved by pressing q (either upper or lower case) or . (dot) after the escape character. Sending the escape character itself is possible by issuing it again. If the command that must follow the escape character doesn't arrive within two seconds, the escape character is ignored, and the terminal will emit a visible flash when supported, to indicate the user that the escape sequence was aborted. A help page is available with h or ?:
$ bt
No port specified, using ttyUSB0 (last registered). Use -l to list ports.
Trying port ttyUSB0... Connected to ttyUSB0 at 115200 bps.
Escape character is 'Ctrl-]'. Use escape followed by '?' for help.
BootTerm supports several single-character commands after the escape character:
H h ?β display this helpQ q .β quitP pβ show port statusD dβ flip DTR pinR rβ flip RTS pinF fβ flip both DTR and RTS pinsB bβ send breakC cβ enable / disable captureT tβ enable / disable timestamps on terminal
Enter the escape character again after this menu to use these commands. π
π§ Waiting for a new serial port π§
Most often you don't want to know what name your serial port will have, you just want to connect to the one you're about to plug, as soon as it's available, in order to grasp most of the boot sequence. That's what bt -n is made for. It will check the list of current ports and will wait for a new one to be inserted. It even works if one port is unplugged and replugged. This is very convenient to avoid having to follow cables on a desk, or when connecting to a device that gets both the power and the console from the same USB connector. It's worth noting that this wait feature is ignored when -l is used to get an instant list of detected ports. π
The automatic port detection is more precise on Linux and FreeBSD where a detailed list of available ports with their respective drivers and descriptions are available. On other operating systems, the automatic detection falls back to a scan of node in /dev, avoiding known unrelated ones, and focusing on specific ones for certain operating systems (e.g. macOS uses cu.*).
Example below booting a Breadbee board with an integrated CH340E adapter after bt -n:
$ bt -n
3 ports found, waiting for a new one...
port | age (sec) | device | driver | description
------+------------+------------+------------------+----------------------
3 | 0 | ttyUSB1 | ch341-uart |
Trying port ttyUSB1... Connected to ttyUSB1 at 115200 bps.
Escape character is 'Ctrl-]'. Use escape followed by '?' for help.
!
U-Boot 2019.07-00068-g18b9e73630-dirty (May 30 2020 - 13:37:48 +0900)
DRAM: 64 MiB
One particularly appreciable case is when connecting to an emulated port, such as below on a NanoPI NEO2 running Armbian:
$ bt -n
2 ports found, waiting for a new one...
port | age (sec) | device | driver | description
------+------------+------------+------------------+----------------------
2 | 0 | ttyACM0 | cdc_acm | CDC Abstract Control Model (ACM)
This port selection mode can be automatically enabled by setting the BT_SCAN_WAIT_NEW environment variable to any value:
$ export BT_SCAN_WAIT_NEW=1
$ bt
3 ports found, waiting for a new one...
π Waiting for any port π
A different approach consists in waiting for either a specific port or any port. By default, issuing bt ttyUSB0 will fail if this terminal doesn't exist yet. But with bt -a ttyUSB0, BootTerm will wait for the device to appear. Just like with -n, this wait feature is ignored when -l is used to get an instant list of detected ports.
With no device name specified, it will wait for any usable device and use the most recent one. If some ports are already on board and must never be used, they can be excluded using the environment variable BT_SCAN_EXCLUDE_PORTS, which is a comma-delimited list of device names, possibly ending with *:
$ export BT_SCAN_EXCLUDE_PORTS=ttyS0,ttyS1
$ bt -a
Waiting for one port to appear...
Port ttyUSB0 available, using it.
port | age (sec) | device | driver | description
------+------------+------------+------------------+----------------------
0 | 0 | ttyUSB0 | ch341-uart |
Trying port ttyUSB0... Connected to ttyUSB0 at 115200 bps.
Escape character is 'Ctrl-]'. Use escape followed by '?' for help.
It is also possible to enable this port selection mode by default using BT_SCAN_WAIT_ANY:
$ export BT_SCAN_EXCLUDE_PORTS=ttyS*
$ export BT_SCAN_WAIT_ANY=1
$ bt
Waiting for one port to appear...
It is probably what most laptop users will want to do so as never to have to pass any argument and automatically connect to a USB serial port. π«Ά
One may also exclude some drivers from the scan using BT_SCAN_EXCLUDE_DRIVERS, which can sometimes be more convenient to ignore some known uninteresting internal devices:
$ bt -l
port | age (sec) | device | driver | description
------+------------+------------+------------------+----------------------
0 | 12562 | ttyACM0 | cdc_acm | Fibocom L830-EB
1 | 99 | ttyS0 | serial |
* 2 | 21 | ttyUSB0 | cp210x | CP2102 USB to UART Bridge Controller
$ BT_SCAN_EXCLUDE_DRIVERS=serial,cdc_acm bt -l
port | age (sec) | device | driver | description
------+------------+------------+------------------+----------------------
* 0 | 24 | ttyUSB0 | cp210x | CP2102 USB to UART Bridge Controller
Alternately, it is possible to restrict the port enumeration to only a specific set by listing them in BT_SCAN_RESTRICT_PORTS. This can be more convenient when you know that your port is always called ttyACM0 or any such thing for example. Similarly these ports can end with * to validate any suffix, such as ttyACM*.
β Changing the baud rate β
On opening, the port's baud rate is automatically changed to the value specified with -b, or in the BT_PORT_BAUD_RATE variable, or by default to 115200 if neither is set. However if the baud rate is explicitly set to 0 (either using -b or using the variable) then the baud rate is unchanged. Example below with a NodeMCU module:
$ bt -b 74880
Port ttyUSB2 available, using it.
port | age (sec) | device | driver | description
------+------------+------------+------------------+----------------------
2 | 524342 | ttyUSB2 | cp210x | CP2102 USB to UART Bridge Controller
Trying port ttyUSB2... Connected to ttyUSB2 at 76800 bps.
Escape character is 'Ctrl-]'. Use escape followed by '?' for help.
ngl it's lowkey iconic that the hardware straight up does not support 74880 bauds and just picked its closest supported speed instead (76800). That's a 2.5% error, and bestie, it will not cause any trouble. π
π Using BootTerm to detect ports
okay so BootTerm has a "print" mode and it's giving main character energy. In this mode it just prints the device name without the leading /dev/. Super convenient as an assistant to other flashing tools that need to wait for a port and then print its name.
By default the newly detected port is reported (so you get the whole lil announcement), which is why it's wise to switch to quiet mode so you don't get all that intermediary info cluttering your vibe:
$ bt -np
4 ports found, waiting for a new one...
ttyUSB2
$ bt -npq
ttyUSB2
So a script that needs to connect to the port as early as possible to reprogram a board could do something like this to wait for the device to show up:
PORT=$(bt -npq)
if [ -n "$PORT" ]; then
flash -p "$PORT" -i "$IMAGE"
fi
β‘ Issuing special sequences
The current port status (name, speed, pins) gets reported when you press p after the escape sequence. Pin names in lower case are in the low state, those in upper case are in the high state. When pin toggling is required, it is wise to check the real pin's polarity, because most circuits invert it multiple times along the chain. The status reported here is the one seen by the serial port driver. π«Ά
A break sequence can be used to trigger the SysRq feature in Linux, or to reboot some boards. The break happens by pressing b after the escape key, e.g. Ctrl-] b. You can also send a break sequence just before starting the terminal by passing -B on the command line. Combined with -N, it may be used to simply program a reset from a script (e.g. bt -aqNB). β¨
The DTR pin can be toggled by pressing D after the escape character, and the RTS pin can be toggled by pressing R. Both pins can be toggled together (for example to reset an ESP8266 in flashing mode) by pressing F. π₯
πΌ Capturing responses
There are two ways of capturing responses. If no terminal is needed, simply redirecting bt's output to a file will work:
$ bt /dev/ttyS0 > server-panic.log
If a terminal is needed and a capture of the session is desired, there's a special capture function. It supports three modes, which are enabled either by -c on the command line, otherwise by environment variable BT_CAPTURE_MODE:
noneβ capture is disabled, this is the defaultfixedβ a file name is fixed on start of the capture and will not changetimedβ the file name is re-evaluated each second and if it changes, the previous file is closed and a new one is opened.
In all cases, the files are only appended to and never truncated, so that BootTerm will never destroy previous traces. If a fresh file is needed, just remove the file before starting BootTerm. π«‘
The fixed mode usually is the one that users will want to capture a session when dumping a boot loader's configuration or the kernel's boot messages. The timed mode can be useful when connecting to a port waiting for rare or periodic events in order to get a dated file. The file name is defined by the format passed to -f, which defaults to the current date and time. It uses strftime() so please check this man page to get all format options supported on your system.
Thus when exploring a new device, one would likely use:
$ bt -c fixed
And when collecting event logs from a server with one file per day:
$ bt -c timed -f "server-%Y%m%d.log"
β±οΈ Timestamps in captures
Timestamps may be enabled in captures, according to the -t command line argument, or the BT_TIMESTAMP_MODE, which may contain one of the following values:
noneβ no timestamp is added, lines are dumped exactly as received, this is the defaultabsβ the date and time of the first character at the beginning of a line are dumped using year,month,day,hour,minute,second,micro enclosed in square brackets at the beginning of the line, followed by a space, such as[20201219-192208.888633].initβ the time of the first character of each line, relative to the start of the program is printed at the beginning of each line using seconds and microseconds inside square brackets followed by a space, such as[ 3.557564]. The seconds are padded on 6 characters, which are enough for 11 days of capture. Above this the field's width will increase.lineβ the time of the first character of each line, relative to the date of the previous line is printed at the beginning of each line using seconds and microseconds inside square brackets followed by a space, such as[ 1.273017]. The seconds are padded on 6 characters, which are enough for 11 days of pause between two lines. Above this the field's width will increase.
Example of capture with line-relative timestamps, showing a kernel decompression time of 1.27 second: capture (Image: doc/kernel-boot.png) πΈ
In addition, timestamps may also be temporarily enabled on the terminal by pressing 'T' after the escape character. The timestamp mode configured above will be used, except if not set, in which case the absolute mode will be used.
β οΈ It is important to understand that timestamps on a terminal will quickly cause trouble on the output since the terminal and the application are seeing different contents and positions. It can be convenient to observe boot times for example, but should be disabled when starting any interactive application (e.g. an editor). π
Please note that there is a subtle difference between terminal timestamp and file-based captures. In file-based captures, the time is taken when the first character is printed after a line feed. This provides the most accurate timing between two consecutive lines because it will take the processing time into account. However on the terminal it cannot be done exactly this way without rendering the terminal very painful to use, because on a typical prompt, the leading timestamp would be missing until the user presses a character that would suddenly cause the timestamp to be printed before it is echoed. Thus on the terminal, the timestamp is calculated when the cursor goes to the beginning of a new line, and is (re-)printed every time the cursor goes to the beginning of the line. This means that on the terminal, the processing time, if any, will usually be accounted as part of the time needed to print the next line.
π Changing the escape character
The escape character may be specified either as a single character after -e or as an integer or hexadecimal value representing the ASCII code of this character.
Users coming from the venerable screen utility will probably want to set the escape character to Ctrl-A (unless of course they want to call screen from within these sessions, or are irritated by the confiscation of this common sequence):
$ bt -e1
Those coming from tmux would rather use Ctrl-B:
$ bt -e2
Here are a few other convenient and less common escape characters:
Ctrl-@β code0β argument-e0Ctrl-Aβ code1β argument-e1Ctrl-Zβ code26β argument-e26Escβ code27β argument-e27Ctrl-\β code28β argument-e28Ctrl-]β code29β argument-e29Ctrl-^β code30β argument-e30Ctrl-_β code31β argument-e31
π‘οΈ Masking problematic characters
Running at wrong speeds or connecting during a boot sequence often results in some garbage being received on a terminal. And different terminal emulators handle these differently. For example, Xterm supports a very large variety of codes in the C1 range (0x80-0x9F) among which CSI (0x9B) which is an escape with the high bit set. The problem is that the prefix range is large and that many of them will result in reconfiguring it or hanging it until a sequence ends. This is often translated into unreadable fonts, the terminal definitely freezing, or arrow keys making the cursor move on the screen instead of being sent to the remote terminal. Other terminals have their own problems with 0x00, 0xFF or can be at risk with improper handling of ANSI codes prefixed with 0x1B. π
In order to address this, BootTerm can block dangerous characters and print them encoded instead. It will always block raw and UTF-8 encoded C1 codes (0x80-0x9F with or without the 0xC2 prefix), as these are always terminal configuration codes which should never be sent to the terminal emulator. In addition it's possible to restrict the range of printable characters using -m and -M. π
Remapping CR to CRLF or LF to CRLF
okay bestie, listen up, because this one is lowkey important and also extremely easy to get wrong π
So in raw mode, terminals emit CR and LF separately and they expect to receive both of them. That goes for your user terminal too, no exceptions. So if the device you're connecting to works in raw mode but doesn't emit CR, or doesn't emit LF, your terminal is gonna get confusing and painful real fast. Like, unusable. π
Enter the environment variable BT_PORT_CRLF β¨ β it forces a remapping of input characters into the CRLF pair everyone actually expects:
BT_PORT_CRLF=0β no remapping. Use case: all the time.BT_PORT_CRLF=1βLFis replaced byCRLF. Use case: when lines look like stairs πͺBT_PORT_CRLF=2βCRis replaced byCRLF. Use case: when the same line always gets overwritten π
Heads up, bestie: to make this play nice with captures and terminal timestamps, the remapping happens inside the port buffer before the captures. Which means the fixed CRLF sequence will show up in your captures. Not a bug, that's just how it is. π«Ά
Most users will never need to change this setting. periodt. π
π REPORTING BUGS π
Found a bug? spill it, bestie π report it to:
https://github.com/wtarreau/bootterm
Β©οΈ COPYRIGHT Β©οΈ
Copyright Β© Willy Tarreau <w@1wt.eu>
and that's a wrap on the whole page, babe π this is BootTerm 0.5-1, dated April 2024, and you're officially a bootterm girlie now. go forth and slay your serial console π β¨π¦
π¦ where this page comes from
- ubuntu resolute: bootterm 0.5-1 Β· MIT
- ubuntu stonking: bootterm 0.5-1 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms