bevy_serialport

Crates.iobevy_serialport
lib.rsbevy_serialport
version0.11.0
created_at2022-08-17 04:17:58.317951+00
updated_at2026-01-14 11:38:49.949489+00
descriptionAsync serial port plugin for Bevy game engine with enhanced error handling and convenience APIs
homepagehttps://github.com/foxzool/bevy_serialport
repositoryhttps://github.com/foxzool/bevy_serialport
max_upload_size
id647135
size160,154
ZoOL (foxzool)

documentation

https://docs.rs/bevy_serialport

README

bevy_serialport

Crates.io Downloads Documentation License CI

Async serial port plugin for the Bevy game engine, providing seamless integration between serial communication and Bevy's ECS system.

Features

  • Async Serial Communication: Non-blocking serial I/O using Tokio
  • 🎯 Event-Driven Architecture: Receive serial data through Bevy events
  • 🔧 Comprehensive Configuration: Full control over serial port settings
  • 🛡️ Enhanced Error Handling: Detailed error types with context
  • 🚀 High Performance: Optimized for minimal overhead
  • 🎮 Multiple Port Support: Manage multiple serial connections simultaneously
  • 🔌 Cross-Platform: Works on Windows, macOS, and Linux
  • 📦 Utility Functions: Built-in helpers for port discovery and validation

Quick Start

Add this to your Cargo.toml:

[dependencies]
bevy_serialport = "0.11"
bevy = "0.18"

Basic Usage

use bevy::prelude::*;
use bevy_serialport::{SerialData, SerialPortPlugin, SerialResource, SerialPortRuntime};
use std::time::Duration;

fn main() {
    App::new()
        .add_plugins((
            DefaultPlugins,
            SerialPortPlugin,
        ))
        .add_systems(Startup, setup_serial)
        .add_systems(Update, handle_serial_data)
        .run();
}

fn setup_serial(
    mut serial_res: ResMut<SerialResource>, 
    rt: Res<SerialPortRuntime>
) {
    // Open a serial port with default settings (115200 baud, 8N1)
    if let Err(e) = serial_res.open(rt.clone(), "COM1", 115_200) {
        error!("Failed to open serial port: {}", e);
    }
}

fn handle_serial_data(
    mut serial_events: MessageReader<SerialData>,
    mut serial_res: ResMut<SerialResource>,
) {
    for event in serial_events.read() {
        info!("Received from {}: {}", event.port, event.as_string_lossy());
        
        // Echo the data back
        let _ = serial_res.send_string(&event.port, "OK\n");
    }
}

Advanced Configuration

use bevy_serialport::{
    SerialPortSetting, DataBits, FlowControl, Parity, StopBits
};
use std::time::Duration;

fn setup_advanced_serial(
    mut serial_res: ResMut<SerialResource>,
    rt: Res<SerialPortRuntime>
) {
    let settings = SerialPortSetting::new("/dev/ttyUSB0", 9600)
        .with_data_bits(DataBits::Seven)
        .with_parity(Parity::Even)
        .with_stop_bits(StopBits::Two)
        .with_flow_control(FlowControl::Software)
        .with_timeout(Duration::from_millis(100));

    match serial_res.open_with_setting(rt.clone(), settings) {
        Ok(_) => info!("Serial port configured successfully"),
        Err(e) => error!("Configuration failed: {}", e),
    }
}

Port Discovery

use bevy_serialport::utils::*;

fn discover_ports() {
    match list_available_ports() {
        Ok(ports) => {
            info!("Available ports:");
            for port in ports {
                info!("  - {}", port);
            }
        }
        Err(e) => error!("Failed to list ports: {}", e),
    }
}

Multiple Ports

fn setup_multiple_ports(
    mut serial_res: ResMut<SerialResource>,
    rt: Res<SerialPortRuntime>
) {
    let ports = vec![
        ("sensor_port", "/dev/ttyUSB0", 9600),
        ("gps_port", "/dev/ttyUSB1", 4800),
        ("debug_port", "COM3", 115200),
    ];

    for (name, port, baud) in ports {
        if let Err(e) = serial_res.open(rt.clone(), port, baud) {
            error!("Failed to open {}: {}", name, e);
        } else {
            info!("Opened {} on {}", name, port);
        }
    }
}

fn handle_multiple_ports(mut serial_events: MessageReader<SerialData>) {
    for event in serial_events.read() {
        match event.port.as_str() {
            "/dev/ttyUSB0" => handle_sensor_data(&event),
            "/dev/ttyUSB1" => handle_gps_data(&event),
            "COM3" => handle_debug_data(&event),
            _ => warn!("Unknown port: {}", event.port),
        }
    }
}

Error Handling

The library provides comprehensive error handling:

use bevy_serialport::SerialError;

fn robust_serial_setup(
    mut serial_res: ResMut<SerialResource>,
    rt: Res<SerialPortRuntime>
) {
    match serial_res.open(rt.clone(), "COM1", 115200) {
        Ok(_) => info!("Port opened successfully"),
        Err(SerialError::SerialPortError { port, source }) => {
            error!("Hardware error on {}: {}", port, source);
        }
        Err(SerialError::InvalidConfiguration { reason }) => {
            error!("Configuration error: {}", reason);
        }
        Err(SerialError::PortNotFound { port }) => {
            error!("Port {} not found", port);
        }
        Err(e) => error!("Other error: {}", e),
    }
}

SerialData API

The SerialData event provides convenient methods for data access:

fn process_serial_data(mut events: MessageReader<SerialData>) {
    for event in events.read() {
        // Get data as string (lossy conversion)
        let text = event.as_string_lossy();
        
        // Try to get data as valid UTF-8 string
        match event.as_string() {
            Ok(valid_text) => info!("Valid UTF-8: {}", valid_text),
            Err(_) => warn!("Invalid UTF-8 data received"),
        }
        
        // Access raw bytes
        let bytes = event.as_bytes();
        info!("Received {} bytes from {}", bytes.len(), event.port);
        
        // Check if empty
        if event.is_empty() {
            warn!("Empty message received");
        }
    }
}

Examples

The repository includes several examples:

  • Basic Receiver: cargo run --example serial_receiver -- --port COM1
  • Basic Sender: cargo run --example serial_sender -- --port COM1
  • Advanced Usage: cargo run --example advanced_usage

Supported Platforms

Platform Status Notes
Windows COM ports (COM1, COM2, etc.)
Linux USB/UART devices (/dev/ttyUSB0, /dev/ttyACM0, etc.)
macOS USB/UART devices (/dev/cu., /dev/tty.)

Bevy Compatibility

Bevy Version bevy_serialport Version
0.18 0.11
0.17 0.10
0.16 0.9
0.15 0.8
0.14 0.7
0.13 0.6
0.12 0.5
0.11 0.4
0.10 0.3
0.9 0.2
0.8 0.1

Common Use Cases

  • 🔬 Scientific Instruments: Communicate with sensors and measurement devices
  • 🤖 Robotics: Control motors, read sensors, and communicate with microcontrollers
  • 🎮 Game Controllers: Interface with custom hardware controllers
  • 📡 IoT Integration: Connect with embedded devices and sensors
  • 🔧 Development Tools: Debug interfaces and diagnostic tools

Performance Considerations

  • Uses Tokio's async runtime for non-blocking I/O
  • Minimal memory allocations in the hot path
  • Efficient message batching for high-throughput scenarios
  • Thread-safe design with minimal locking overhead

Troubleshooting

Port Not Found

# Linux: Check available ports
ls /dev/tty*

# Windows: Use Device Manager or PowerShell
Get-WmiObject -Class Win32_SerialPort | Select-Object Name,DeviceID

Permission Denied (Linux)

# Add user to dialout group
sudo usermod -a -G dialout $USER
# Then logout and login again

Port Already in Use

Ensure no other applications are using the serial port. On Linux, you can check with:

lsof /dev/ttyUSB0

Contributing

We welcome contributions! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests if applicable
  5. Submit a pull request

License

This project is dual-licensed under either:

At your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Acknowledgments

  • Built on top of tokio-serial for async serial communication
  • Inspired by the Bevy community's commitment to ergonomic game development
  • Thanks to all contributors and users who have helped improve this library

For more information, visit the documentation or check out the repository.

Commit count: 49

cargo fmt