Serial port doesn't properly open on Windows 11
danijourdain opened this issue · 5 comments
I'm writing a program to communicate with an Arduino over a serial port. Immediately after flashing the Arduino or plugging it into a computer my Rust code doesn't actually open the serial port. The code runs without error but I receive nothing from the Arduino.
Here is the Arduino code. It should just echo back what I'm writing into Serial1, which I am monitoring using TeraTerm.
void setup() {
// Initialize both serial ports:
Serial.begin(115200);
Serial1.begin(115200);
}
void loop() {
// Check if data is available on the main Serial port:
if (Serial.available() > 0) {
char incomingByte = Serial.read(); // Read the incoming byte
Serial.print(incomingByte); // Echo it back on the main Serial port
Serial1.print(incomingByte); // Echo it on Serial1
}
}
And here is the Rust code I'm using.
use std::{io::Write, time::Duration};
fn main() {
println!("Hello, world!");
let mut port = serialport::new("\\.\\COM10", 115_200)
.timeout(Duration::from_millis(10))
.open_native()
.expect("Failed to open port");
port.write("This is a test".as_bytes()).unwrap();
println!("Goodbye, world!");
}
When I run the Rust code, it executes successfully but I see nothing on TeraTerm. When I write to the serial port using Arduino's serial monitor or a Python script the expected output is seen on TeraTerm. I've also tried using .open()
instead of .open_native()
as well as using "COM10" instead of "\.\COM10".
If I open the serial port using some other method (Arduino IDE, Python, etc.) and then run the Rust code, it works as intended. Is there a way I can get it to work in Rust without opening the port some other way first?
I've noticed this issue does not happen on Linux
Hello @danijourdain, at a first glance it might be the case that the data gets written from the applications perspective and just not makes it onto the serial wire. Just writing and closing the serial port (by dropping it at the end of main
) might not be enough. Could you please try two things:
-
Force outputting the data by calling
flush
after writing likeport.write("This is a test".as_bytes()).unwrap(); port.flush().unwrap();
-
Adding some delay after flushing and before leaving
main
likeport.write("This is a test".as_bytes()).unwrap(); port.flush().unwrap(); std::thread::sleep(std::time::Duration::from_secs(1)); println!("Goodbye, world!"); }
as we've seen issues on macOS in #117 where flushing alone did not suffice to get the data on the wite in a similar scenario
I've noticed this issue does not happen on Linux
Sounds likely as Linux cares very much for getting your data on the wire is this scenario (
#117 (comment)).
Hi @sirhcel. Thank you so much for your quick response.
Neither of those suggestions ended up working. However, I did end up finding a solution!
Adding this line along with a delay seems to do this trick.
port.write_data_terminal_ready(true)?;
std::thread::sleep(Duration::from_millis(1500));
Great to hear that you managed to resolve this issue on your own! In my bubble a serial interface is often just RX/TX and I would have expected the same for an Arduino device.
Just for curiosity: How does your serial setup/wiring look like? Are you using a UART with all the control lines? Or a USB serial stack on the Arduino device?
I'm using a Teensy4.1 running Teensyduino to appear and behave as an Arduino device. I wonder if that's part of the strange behaviour. I didn't have an Arduino available to confirm that unfortunately.
I'm using the microUSB port included on the Teensy for all data being sent by the computer. I have a UART to USB converter that I connect to the control pins for Serial1 on the Teensy to use for debugging/extra logging info in more complicated applications.