A professional serial terminal with dual ASCII/HEX view, real-time plotting, binary/frame decoding, data converter, and configurable macro buttons. Built with Python and PyQt5.
- Auto-detect serial ports with device name and VID:PID display
- Configurable baud rate (9600 to 921600), data bits, parity, stop bits, flow control
- Auto-reconnect when an unplugged USB device reappears (View > Auto-Reconnect)
- Visual connection indicator (DB-9 connector icon: green = connected, red = disconnected)
- Live status bar with RX/TX throughput (bytes/sec), totals, and baud rate
- Timestamped logging to file (Record button / Ctrl+R), one log line per device line
- ASCII and HEX views side by side, updated in real-time (batched at ~30 fps, so the GUI stays responsive at high baud rates)
- Color-coded: red for received data, blue for sent data
- Scroll position and text selection are preserved while data streams in; the view only auto-scrolls when already at the bottom
- Search/highlight in scrollback (Ctrl+F)
- Resizable splitter between the plot and data views
- Three send modes: ASCII, HEX, BINARY
- Configurable line endings: None, LF, CR, CR+LF
- Command history with Up/Down arrow keys
- 8 macro buttons for quick-send (right-click to edit label and payload)
- 1 to 12 channels with auto-scaling Y-axis
- Configurable scrolling window (10 to 10,000 points)
- High-throughput rendering: samples are batched into preallocated numpy
buffers and each curve redraws once per display frame (~30 fps) with
peak-preserving downsampling, independent of the incoming sample rate.
Binary streams are decoded vectorized (
np.frombuffer, no per-sample Python), so the plot keeps up with multi-MB/s USB-CDC sources, far beyond any real serial baud rate - Dual Y-axes: right-click a legend entry to move a channel to Y2 (dashed)
- Per-channel show/hide toggle checkboxes below the plot
- Per-channel scale / offset / unit (right-click a legend entry): plotted value = raw x scale + offset, with the unit shown in the legend and crosshair
- Time-based X-axis ("Time X" checkbox): label the axis in seconds using the measured sample rate, instead of the sample index
- Math/computed channels with numpy expressions (e.g.
ch0 * ch1); expressions are validated against a whitelist and compiled once - FFT frequency spectrum view (Hann window, amplitude-normalized)
- Pause button and oscilloscope-style trigger mode (level + edge, centered)
- Crosshair cursor showing all channel values at the mouse position
- Right-click legend entries to rename channels or change colors
- Right-click plot area for axis settings (auto-range, manual Y-axis limits)
- Clear Plot button to reset all data
- Export plot as PNG image
- Export plot data as CSV with channel name headers
ASCII (default) -- Parses newline-delimited text values for plotting.
| Delimiter | Example |
|---|---|
| Auto-detect | Detects tab, comma, semicolon, or space |
| Comma | 1.0,2.0,3.0 |
| Semicolon | 1.0;2.0;3.0 |
| Space | 1.0 2.0 3.0 |
| Tab | 1.0\t2.0\t3.0 |
| Other | User-defined custom delimiter |
Supports labeled values (e.g., temp:23.5,hum:45.2). A non-numeric or empty
field is plotted as a gap so the remaining values stay on their own channels.
Binary Stream -- Decodes continuous raw binary data.
| Setting | Options |
|---|---|
| Data Type | uint8, int8, uint16, int16, uint32, int32, float32, double64 |
| Endianness | Little Endian, Big Endian |
| Sync | Button to re-align stream |
Each sample is channels x sizeof(type) bytes. In this mode, the left panel shows color-coded decoded channel values.
Custom Frame -- Decodes framed binary packets.
Frame structure: [Start Byte(s)] [Optional Size Field] [Payload] [Optional Checksum]
| Setting | Options |
|---|---|
| Start byte | Variable-length hex sequence (e.g., AA BB) |
| Payload Size | Fixed (user-specified), 1-byte size field, 2-byte size field |
| Data Type | Same 8 types as Binary Stream |
| Endianness | Little Endian, Big Endian |
| Checksum | Optional 8-bit sum validation |
- Real-time conversion between HEX, ASCII, Decimal, and Binary
- 12 conversion combinations
- Input/output with arrow indicator
- All settings saved automatically to
AxxTerm_settings.json(writes are debounced so rapid changes coalesce into one disk write) - Includes: serial port config, decode mode, plot settings, channel names/colors/axes/visibility, math channels, macros, dark mode, and window/splitter geometry
- File > Save Settings / Load Settings for explicit save/load to custom files
| Shortcut | Action |
|---|---|
| Enter | Send data |
| Up/Down | Navigate send history |
| Ctrl+F | Find in scrollback |
| Ctrl+R | Start/stop recording to log file |
| Ctrl+D | Toggle dark mode |
| Ctrl+S | Save settings to file |
| Ctrl+O | Load settings from file |
| Ctrl+Q | Quit |
- Python 3.8+
- PyQt5 >= 5.15
- pyqtgraph >= 0.13
- NumPy >= 1.24
git clone https://github.com/AxxAxx/AxxTerm.git
cd AxxTerm
pip install -r requirements.txt
python AxxTerm.pyNo Python installation is needed on the target machine. Build a single portable executable with PyInstaller:
pip install pyinstaller
pyinstaller --onefile --windowed --name AxxTerm --clean AxxTerm.pyThis creates dist/AxxTerm.exe. Copy it anywhere and run.
- The .exe resolves config files relative to the executable location, not the temp folder
- First launch creates
AxxTerm_settings.jsonnext to the executable when you change any setting - File size is typically 30-50 MB (includes Python runtime and all dependencies)
| File | Description |
|---|---|
AxxTerm.py |
Main application (single-file, self-contained) |
tests/test_axxterm.py |
Headless tests (decoders, parsing, plot path, settings) |
requirements.txt |
Python dependencies |
AxxTerm_GUI.PNG |
Screenshot |
LICENSE |
MIT License |
The tests run headless via Qt's offscreen platform (no display needed) and use a throwaway settings file:
QT_QPA_PLATFORM=offscreen python tests/test_axxterm.pyOn Windows PowerShell:
$env:QT_QPA_PLATFORM = "offscreen"; python tests/test_axxterm.pyThey cover the binary/frame/ASCII decoders (including chunk boundaries and resync), the hex formatter, the math-expression sandbox, per-channel scale/offset, the time-axis sample-rate measurement, and a settings round-trip.
AxxTerm_settings.json is auto-created and contains:
{
"dark_mode": false,
"auto_reconnect": true,
"window": { "geometry": "<hex>", "splitter": [300, 400] },
"plot": {
"mode": "ASCII",
"num_channels": 4,
"num_points": 100,
"show_plot": false,
"show_fft": false,
"delimiter": "Auto",
"channel_names": {},
"channel_colors": {},
"channel_axes": {},
"channel_scale": {},
"channel_offset": {},
"channel_units": {},
"hidden_channels": [],
"x_time_mode": false,
"y_auto_scale": true,
"math_channels": [],
"binary": { "data_type": "float32", "endianness": "little" },
"frame": { "sync_word": "AA", "size_field": "fixed", "frame_size": 12, "checksum": false }
},
"serial": {
"baud_rate": "115200",
"data_bits": 3,
"parity": 0,
"stop_bits": 0,
"flow_control": 0
},
"macros": [
{ "label": "0x7F", "hex": "7F" }
]
}MIT License. See LICENSE for details.