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?