serialport / serialport-rs

A cross-platform serial port library in Rust. Provides a blocking I/O interface and port enumeration including USB device information.
Other
483 stars 115 forks source link

Serial port doesn't properly open on Windows 11 #204

Open danijourdain opened 2 months ago

danijourdain commented 2 months ago

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?

danijourdain commented 2 months ago

I've noticed this issue does not happen on Linux

sirhcel commented 2 months ago

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:

  1. Force outputting the data by calling flush after writing like

    port.write("This is a test".as_bytes()).unwrap();
    port.flush().unwrap();
  2. Adding some delay after flushing and before leaving main like

        port.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 ( https://github.com/serialport/serialport-rs/issues/117#issuecomment-1704451842).

danijourdain commented 2 months ago

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));
sirhcel commented 2 months ago

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?

danijourdain commented 2 months ago

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.