最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

rust - Opening a COM port to read data in Windows - Stack Overflow

programmeradmin2浏览0评论

I am using the Windows crate and trying to open a COM port. This is what I have done so far:

use tokio::task;
use windows::core::HSTRING;
use windows::Devices::SerialCommunication::{SerialHandshake, SerialParity, SerialStopBitCount};
use windows::Storage::Streams::{DataReader, InputStreamOptions};
use windows::Win32::Foundation::E_FAIL;
use windows::{
    Devices::Enumeration::DeviceInformation, Devices::SerialCommunication::SerialDevice,
};

#[tokio::main]
async fn main()
    // Open the SerialDevice from the COM port number
    let port_number = HSTRING::from("COM12");
    let baud_rate = 9600;
    let data_bits = 8;
    let parity = SerialParity::None;
    let stop_bits = SerialStopBitCount::One;
    let handshake = SerialHandshake::None;

    let selector_from_port = SerialDevice::GetDeviceSelectorFromPortName(&port_number)?;

    // Get device collection
    let device_collection = DeviceInformation::FindAllAsyncAqsFilter(&selector_from_port)?.get()?;

    // Get DeviceInformation clearly
    let device_info = match device_collection.into_iter().next() {
        Some(info) => info,
        None => return Err(windows::core::Error::new(E_FAIL, "Device not found")),
    };

    // Clearly log Device ID for debugging
    let device_id = device_info.Id()?;
    println!("Opening device with ID: {}", device_id);

    // Explicitly open SerialDevice with clear error handling
    let async_op = SerialDevice::FromIdAsync(&device_id)?;

    let serial_device = async_op.get().map_err(|e| {
        windows::core::Error::new(E_FAIL, format!("Failed to open SerialDevice: {}", e))
    })?;

    println!("Successfully opened port: {}", serial_device.PortName()?);

    serial_device.SetBaudRate(baud_rate)?;
    serial_device.SetDataBits(data_bits)?;
    serial_device.SetParity(parity)?;
    serial_device.SetStopBits(stop_bits)?;
    serial_device.SetHandshake(handshake)?;

    println!("Port Name {}", serial_device.PortName()?);

    // Watch for incoming data
    let input_stream = serial_device.InputStream()?;

    let reader = DataReader::CreateDataReader(&input_stream)?;

    // Set the read options
    reader.SetInputStreamOptions(InputStreamOptions::Partial)?;

    loop {
        // Load available bytes asynchronously
        let bytes_read = task::spawn_blocking({
            let reader = reader.clone();
            move || reader.LoadAsync(1024)?.get()
        })
        .await
        .map_err(|e| windows::core::Error::new(windows::core::HRESULT(0), e.to_string()))??;

        if bytes_read > 0 {
            let mut buffer = vec![0u8; bytes_read as usize];
            reader.ReadBytes(&mut buffer)?;

            // Convert buffer bytes to HEX string
            let hex_string: String = buffer.iter().map(|byte| format!("{:02X} ", byte)).collect();

            println!("Read {} bytes: {}", bytes_read, hex_string.trim());
        } else {
            // No data available yet
            tokio::time::sleep(std::time::Duration::from_millis(100)).await;
        }
    }
}

And my dependences are

[package]
name = "win32-rs"
version = "0.1.0"
edition = "2024"

[dependencies]
windows = { version = "0.60.0", features = ["Devices_SerialCommunication", "Devices_Enumeration", "Foundation", "Storage_Streams", "Win32"] }
tokio = { version = "1.44.1", features = ["full"] }

I am able to run the code but I get an error as Error: Error { code: HRESULT(0x80004005), message: "Failed to open SerialDevice: The operation completed successfully. (0x00000000)" }. Looking at the documentation - - 0x00000000 is S_OK and not E_FAIL.

I am not sure where I am wrong. How should I make sure that the port opens and read the data?

发布评论

评论列表(0)

  1. 暂无评论