A C++ shared-library plugin that exposes a general-purpose UART serial interface through a unified command dispatcher. The plugin supports sending and receiving data over a serial port using inline command expressions or external script files, and provides runtime reconfiguration of port parameters without reloading the plugin.
Version: 1.0.0.0
- Overview
- Project Structure
- Architecture
- Building
- Command Reference
- CMD Expression Syntax
- Script Files
- Fault-Tolerant and Privileged Modes
- Error Handling and Return Values
The plugin loads as a dynamic shared library (.so / .dll). The host application calls the exported C entry points pluginEntry() / pluginExit() to create and destroy the plugin object. Once loaded, the host passes configuration settings (serial port, baud rate, timeouts, buffer size…) via setParams(), optionally calls doInit(), and then calls doDispatch() for every command it wants to execute.
All commands follow the pattern:
<PLUGIN>.<COMMAND> [arguments]
For example:
UART.CONFIG p:/dev/ttyUSB0 b:115200 r:2000 w:2000 s:1024
UART.CMD > "AT\r\n" | "OK"
UART.CMD < "Please send!" | Sending...
UART.SCRIPT handshake.txt
uart_plugin/
├── CMakeLists.txt # Build definition (shared library)
├── inc/
│ └── uart_plugin.hpp # Class definition, command table, public accessors
└── src/
└── uart_plugin.cpp # Entry points, command handlers, init/cleanup, send/receive
The plugin is intentionally compact: a single implementation file handles all four commands, send/receive helpers, parameter loading, and the script engine integration.
pluginEntry() → creates UARTPlugin instance
setParams() → loads INI values (port, baud rate, timeouts, buffer size...)
doInit() → marks plugin as initialized (no hardware opened yet)
doEnable() → enables real execution (without this, commands validate args only)
doDispatch(cmd, args) → routes a command string to the correct handler
doCleanup() → marks plugin as uninitialized and disabled
pluginExit(ptr) → deletes the UARTPlugin instance
Note: Unlike many other plugins,
doInit()does not open the UART port. The port is opened on demand inside eachCMDandSCRIPTcall using RAII — theUARTdriver object opens on construction and closes on destruction. This means a single plugin instance can address different ports across different commands simply by callingCONFIGbetween them.
doEnable() controls a "dry-run / validation" mode: when not enabled, every command validates its arguments and returns true without performing any I/O. This allows test frameworks to verify command syntax before the device is connected.
Commands are registered via a single-level std::map (m_mapCmds) populated in the constructor through an X-macro expansion:
#define UART_PLUGIN_COMMANDS_CONFIG_TABLE \
UART_PLUGIN_CMD_RECORD( INFO ) \
UART_PLUGIN_CMD_RECORD( CONFIG ) \
UART_PLUGIN_CMD_RECORD( CMD ) \
UART_PLUGIN_CMD_RECORD( SCRIPT )
// In the constructor:
#define UART_PLUGIN_CMD_RECORD(a) \
m_mapCmds.insert(std::make_pair(#a, &UARTPlugin::m_UART_##a));
UART_PLUGIN_COMMANDS_CONFIG_TABLE
#undef UART_PLUGIN_CMD_RECORDAdding a new top-level command requires only a new entry in the config table and a corresponding handler implementation.
The CMD command delegates argument parsing and execution to the CommScriptCommandValidator and CommScriptCommandInterpreter framework components, which handle the full send/receive expression grammar. The SCRIPT command similarly delegates multi-command file execution to CommScriptClient.
The following keys are read from the host configuration/INI file at setParams() time:
| Key | Type | Description |
|---|---|---|
UART_PORT |
string | Serial port path (e.g., /dev/ttyUSB0, COM3) |
BAUDRATE |
uint32 | Baud rate (e.g., 9600, 115200, 921600) |
READ_TIMEOUT |
uint32 | Per-read timeout in milliseconds |
WRITE_TIMEOUT |
uint32 | Per-write timeout in milliseconds |
READ_BUF_SIZE |
uint32 | Receive buffer size in bytes |
READ_BUF_TIMEOUT |
uint32 | Buffer-drain timeout for bulk receive operations |
ARTEFACTS_PATH |
string | Base directory from which script file paths are resolved |
All of these values can also be overridden at runtime using the CONFIG command without reloading the plugin.
The plugin is built as a CMake shared library. It links against uIPlugin, uICoreScript, uCommScriptClient, uCommScriptCommandInterpreter, uScriptReader, uPluginOps, and uUart, which must be available in the CMake build tree.
mkdir build && cd build
cmake ..
make uart_pluginThe output is libuart_plugin.so (Linux) or uart_plugin.dll (Windows).
Prints version information and a concise usage summary of all supported commands directly to the logger. This command takes no arguments and works even if doInit() failed (i.e., no hardware is required).
UART.INFO
Example output:
UART_PLUGIN| Version: 1.0.0.0
UART_PLUGIN| Description: communicate with other apps/devices via UART
UART_PLUGIN| CONFIG : overwrite the default UART port
UART_PLUGIN| Args : [p:port] [b:baudrate] [r:read_tout] [w:write_tout] [s:recv_bufsize]
UART_PLUGIN| Usage: UART.CONFIG p:COM2 b:115200 r:2000 w:2000 s:1024
UART_PLUGIN| SCRIPT : send commands from a file
UART_PLUGIN| Args : script
UART_PLUGIN| Usage: UART.SCRIPT script.txt
UART_PLUGIN| CMD : send, receive or both
UART_PLUGIN| Args : direction message
UART_PLUGIN| Usage: UART.CMD > H"AABBCCDD" | ok
UART_PLUGIN| UART.CMD < "Please send!" | F"data.bin, 1024"
Overrides the UART connection parameters at runtime. Any subset of parameters can be specified; omitted keys retain their current values. This is particularly useful when switching between different serial ports or baud rates within the same test sequence.
UART.CONFIG [p:<port>] [b:<baudrate>] [r:<read_timeout>] [w:<write_timeout>] [s:<recv_bufsize>]
| Token | INI key | Description |
|---|---|---|
p:<port> |
UART_PORT |
Serial port path or name |
b:<baudrate> |
BAUDRATE |
Baud rate |
r:<ms> |
READ_TIMEOUT |
Read timeout in milliseconds |
w:<ms> |
WRITE_TIMEOUT |
Write timeout in milliseconds |
s:<bytes> |
READ_BUF_SIZE |
Receive buffer size in bytes |
# Full reconfiguration for a Windows virtual COM port
UART.CONFIG p:COM2 b:115200 r:2000 w:2000 s:1024
# Linux USB serial device at a different baud rate
UART.CONFIG p:/dev/ttyUSB0 b:921600
# Change only the read timeout
UART.CONFIG r:5000
# Switch port and buffer size, keep other settings
UART.CONFIG p:/dev/ttyACM1 s:2048
Executes a single send/receive command over the UART port. The port is opened for the duration of the call and closed automatically when the command completes. The expression syntax supports sending strings, hex data, or files, and receiving into fixed buffers, token-matched data, or line-terminated responses.
UART.CMD <expression>
See CMD Expression Syntax for the full grammar.
# Send "AT\r\n" and expect to read back "OK"
UART.CMD > "AT\r\n" | "OK"
# Wait to receive the string "Please send!" then transmit "Sending..."
UART.CMD < "Please send!" | Sending...
# Send a raw hex stream with no expected response
UART.CMD > H"AABBCCDD"
# Send a file and capture the response into another file
UART.CMD > F"command.bin" | F"response.bin, 1024"
Executes a multi-command script file from the ARTEFACTS_PATH directory. Each line in the file contains one CMD expression. An optional inter-command delay (in milliseconds) can be specified.
UART.SCRIPT <filename> [<delay>]
filename— script file name, resolved relative toARTEFACTS_PATH.delay— optional delay in milliseconds inserted between each command line. Defaults to0.
# Run a script with no delay between commands
UART.SCRIPT handshake.txt
# Run a script with a 100 ms delay between each command
UART.SCRIPT modem_init.txt 100
# Run a longer initialization sequence with a 500 ms delay
UART.SCRIPT firmware_update.txt 500
The CMD command (and each line of a SCRIPT file) uses a structured expression grammar parsed by the CommScriptCommandValidator / CommScriptCommandInterpreter components.
The first token of an expression sets the transfer direction:
| Operator | Description |
|---|---|
> |
Send — transmit data to the device |
< |
Receive — wait to receive data from the device |
A | (pipe) separator follows the first operand and introduces the second operand, which describes the counterpart operation (e.g., what to expect after sending, or what to send after receiving).
The following data formats are supported as operands:
| Format | Syntax | Direction | Description |
|---|---|---|---|
| Plain string | Hello |
send / receive | Unquoted ASCII token; spaces end the token |
| Quoted string | "Hello World\r\n" |
send / receive | Quoted ASCII string; escape sequences supported |
| Hex stream | H"AABBCCDD" |
send / receive | Raw bytes expressed as a hex string |
| File | F"filename, size" |
send / receive | Binary file from ARTEFACTS_PATH; size is byte count for receive |
The | pipe operator chains a send with a receive (or vice versa) in a single atomic command:
> <send_data> | <expected_response>
< <expected_receive> | <response_to_send>
Send then expect:
# Send a string literal, then expect a plain token response
UART.CMD > "AT\r\n" | "OK\r\n"
# Send a hex command byte, then expect a hex acknowledgement
UART.CMD > H"01" | H"06"
# Send a file payload, then expect a specific response token
UART.CMD > F"payload.bin" | "ACK"
Receive then respond:
# Wait for a specific prompt string, then send a response
UART.CMD < "login: " | "admin\r\n"
# Wait to receive a hex token, then send a file
UART.CMD < H"AA55" | F"firmware.bin"
# Wait for a prompt, then send a plain reply
UART.CMD < "Ready?" | "Go!\r\n"
Send or receive only (no pipe):
# Transmit only — no response expected
UART.CMD > "RESET\r\n"
# Receive only — read into a file (1024 bytes)
UART.CMD < F"capture.bin, 1024"
Script files are plain text files stored under ARTEFACTS_PATH. Each non-empty line contains one CMD expression using the same syntax as the CMD command argument. Lines are executed sequentially by CommScriptClient. The optional delay argument to SCRIPT inserts a pause between each line.
Example script (handshake.txt):
> "AT\r\n" | "OK\r\n"
> "AT+GMR\r\n" | "version"
< "Ready" | "GO\r\n"
> H"01020304" | H"06"
Run it with:
UART.SCRIPT handshake.txt
UART.SCRIPT handshake.txt 50
- Fault-tolerant mode (
setFaultTolerant()/isFaultTolerant()): when set, the host framework continues executing subsequent commands even after this plugin returnsfalse. Useful in sequences where a non-response from the device should be logged but not abort the entire test. - Privileged mode (
isPrivileged()): always returnsfalsein this plugin. Reserved for future use in the plugin framework.
Every command handler returns bool:
true— command executed successfully, or argument validation passed in disabled (dry-run) mode.false— argument validation failed, the UART port could not be opened, a send or receive operation timed out or returned an unexpected result, a script file was not found or was empty, or a memory allocation failure occurred.
Errors are emitted via LOG_PRINT at LOG_ERROR severity. Configuration and parameter loading issues are logged at LOG_WARNING or LOG_VERBOSE. The host application controls log verbosity through the shared uLogger configuration.