| Crates.io | aoba |
| lib.rs | aoba |
| version | 0.0.15 |
| created_at | 2025-08-09 15:29:30.446438+00 |
| updated_at | 2025-12-15 09:44:19.521968+00 |
| description | Multi-protocol debugging and simulation CLI/TUI tool for Modbus RTU. |
| homepage | |
| repository | https://github.com/celestia-island/aoba |
| max_upload_size | |
| id | 1788042 |
| size | 1,409,071 |
EN | ZH
Multi-protocol debugging and simulation tool for Modbus RTU, suitable for both physical serial ports and network-forwarded ports. Provides both CLI and TUI interfaces.
--list-ports / --check-port), master/slave operations (--master-provide / --slave-listen) and persistent modes (--*-persist). Outputs can be JSON/JSONL, which is script/CI-friendly.Ctrl+S saves and auto-enables ports) and IPC integration with CLI for testing and automation.socat), HTTP, MQTT, IPC (Unix domain sockets / named pipes), files, and FIFOs.scripts/socat_init.sh for virtual serial ports and example tests in examples/cli_e2e and examples/tui_e2e for local/CI testing.Note: use
--no-config-cacheto disable TUI save/load;--config-file <FILE>and--no-config-cacheare mutually exclusive.
Install the Rust toolchain
Clone the repo and enter the directory
Install:
Build from source: cargo install aoba
Or install a CI-built release (if available) with cargo-binstall:
Example: cargo binstall --manifest-path ./Cargo.toml --version <version>
Use --target <triple> to pick a platform-specific artifact (e.g. x86_64-unknown-linux-gnu).
Run aoba to start the TUI by default; use TUI to configure ports and save the configuration as needed.
--config-file <FILE> explicitly selects a TUI config file (daemon mode uses --daemon-config <FILE>). This conflicts with --no-config-cache, which disables loading/saving of TUI config.
Example:
# Start TUI with a specific config file; load/save enabled
aoba --tui --config-file /path/to/config.json
# Start TUI with no config caching (default) — no load/save
aoba --tui --no-config-cache
Run headless with a saved configuration:
aoba --daemon --config-file /path/to/config.json
Systemd example:
[Unit]
Description=Aoba Modbus RTU Daemon
Wants=network.target
After=network.target network-service
StartLimitIntervalSec=0
[Service]
Type=simple
WorkingDirectory=/home/youruser
ExecStart=/usr/local/bin/aoba --daemon --config-file /home/youruser/config.json
Restart=always
RestartSec=1s
[Install]
WantedBy=multi-user.target
Aoba provides a trait-based Rust API for embedding Modbus functionality in your applications. The API supports both master (client) and slave (server) roles with customizable hooks and data sources.
Modbus Master (polling a slave):
use aoba::api::modbus::{ModbusBuilder, RegisterMode};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Create and start a master that polls a slave
let master = ModbusBuilder::new_master(1)
.with_port("/dev/ttyUSB0")
.with_register(RegisterMode::Holding, 0, 10)
.start_master(None, None)?;
// Receive responses via iterator interface
while let Some(response) = master.recv_timeout(std::time::Duration::from_secs(2)) {
println!("Received: {:?}", response.values);
}
Ok(())
}
Modbus Slave (responding to requests):
use aoba::api::modbus::{ModbusBuilder, RegisterMode};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Create and start a slave that responds to master requests
let slave = ModbusBuilder::new_slave(1)
.with_port("/dev/ttyUSB0")
.with_register(RegisterMode::Holding, 0, 10)
.start_slave(None)?;
// Receive request notifications via iterator interface
while let Some(notification) = slave.recv_timeout(std::time::Duration::from_secs(10)) {
println!("Processed request: {:?}", notification.values);
}
Ok(())
}
Method 1: Using the test script (recommended)
A Python test script is provided to run both master and slave examples simultaneously with colored, prefixed output:
# Run for 30 seconds
python3 scripts/run_api_test.py --duration 30
# Run indefinitely (Ctrl+C to stop)
python3 scripts/run_api_test.py
# Custom ports
python3 scripts/run_api_test.py --master-port /dev/ttyUSB0 --slave-port /dev/ttyUSB1
# Skip auto-build (use existing binaries)
python3 scripts/run_api_test.py --no-build
Note: You may see "Operation timed out" warnings in the logs. This is normal behavior:
- The slave times out while waiting for master requests (1s timeout)
- The master times out while waiting for slave responses (2s timeout)
- Both automatically retry and continue operation
- Communication succeeds despite these warnings
Method 2: Manual execution
Run in separate terminals:
# Terminal 1: Start slave first
cargo run --package api_slave -- /tmp/vcom2
# Terminal 2: Start master
cargo run --package api_master -- /tmp/vcom1
Note: On Linux/WSL, initialize virtual serial ports first:
./scripts/socat_init.sh
For full examples with middleware hooks and data sources, see:
examples/api_master - Master with logging hooksexamples/api_slave - Slave with request monitoring and statistics