Scroll to navigation

BOOTTERM(1) User Commands BOOTTERM(1)

NAME

BootTerm - simple terminal to ease connections with SBCs

SYNOPSIS

bt [options] [/dev/ttyXXX | port#]

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.

  • 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. 74880 bauds 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

OPTIONS

display this help
quiet mode: do not report events
only print selected port name and quit
list detected serial ports and quit
wait for a port to be available (BT_SCAN_WAIT_ANY)
wait for a new port to be registered (BT_SCAN_WAIT_NEW)
specify lowest printable character (default: 0)
specify highest printable character (default: 255)
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)

enable timestamps in terminal (see -t for formats)
escape character or ASCII code (default: 29 = Ctrl-])
capture file name (default: 'bootterm-%Y%m%d-%H%M%S.log')
show version and license
send a break sequence before starting the terminal
do not launch the terminal, just quit
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 help
Q q . quit
P p show port status
D d flip DTR pin
R r flip RTS pin
F f flip both DTR and RTS pins
B b send break
C c enable / disable capture
T 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.

It is interesting to note above that the hardware does not support 74880 bauds and selected its closest support speed (76800). This is a 2.5% error, it will not cause any trouble.

Using BootTerm to detect ports

BootTerm supports a “print” mode. In this mode it will simply print the device name without the leading /dev/. It can be convenient as an assistant to other flashing tools to wait for a port and print its name. By default the newly detected port is reported however, and it is wise to switch to quiet mode to avoid intermediary information:

$ bt -np
4 ports found, waiting for a new one...
ttyUSB2

$ bt -npq
ttyUSB2

Thus a script that needs to connect to the port as early as possible to reprogram a board could be doing 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) is reported when pressing p after the escape sequence. Pin names in lower cases 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, as most circuits invert it multiple times along the chain. The reported status 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. It is also possible to 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 is 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 default

  • fixed: a file name is fixed on start of the capture and will not change

  • timed: 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 default

  • abs : 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:

Sequence Code Argument
Ctrl-@ 0 -e0
Ctrl-A 1 -e1
Ctrl-Z 26 -e26
Esc 27 -e27
Ctrl-\ 28 -e28
Ctrl-] 29 -e29
Ctrl-^ 30 -e30
Ctrl-_ 31 -e31

Masking problematic characters

Running at wrong speeds or connecting during a boot sequence often results in some garbage to be 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 unreadble 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

In raw mode, terminals emit CR and LF separately and expect them both to be received. This is true as well for the user terminal. If the device being connected to works in raw mode but does not emit CR or does not emit LF, then the user terminal will quickly be confusing and painful to use. An environment variable, BT_PORT_CRLF may be used to force a remapping of input characters to the expected CRLF pair:

BT_PORT_CRLF Behavior Use case
0 no remapping all the time
1 LF is replaced by CRLF when lines look like stairs
2 CR is replaced by CRLF when the same line always gets overwritten

Note that in order to make this compatible with captures and terminal timestamps, the remapping is performed inside the port buffer before the captures, and as such the fixed CRLF sequence will appear in the captures.

Most users will never need to change this setting.

REPORTING BUGS

Report bugs to <https://github.com/wtarreau/bootterm>

COPYRIGHT

Copyright © Willy Tarreau <w@1wt.eu>

April 2024 BootTerm 0.5-1+b1