Can't get tokio-serial to work on Win 10 or in the WSL

I'm having difficulty opening opening a serial port using tokio-serial on Win 10. Both the Windows build and the WSL/Debian build. It's a USB serial adapter with an FTDI chip. I can echo characters to it successfully from the Windows command prompt and from the Debian shell in WSL.

The code, boiled down, looks like this:

pub async fn test(tty_path: &str) -> Result<()> {
    let settings = tokio_serial::SerialPortSettings::default();
    match tokio_serial::Serial::from_path(tty_path, &settings) {          // FAILS!!!
        Ok(_serial) => {println!("Serial open")},
        Err(e) => {error!("{:?}", e)}, 
    };
    sleep(Duration::from_millis(1000)).await;
    Ok(())
}

pub fn scan_ports() -> Result<()> {
    match available_ports() {
        // ...
        // Does indeed find my port.
        //
    }
}

#[tokio::main]
async fn main() ->  Result<()> {
    // Print available serial ports.
    scan_ports().unwrap();

    // Spawn a task to get the work done.
    let work_handle = tokio::spawn(async move {
        loop {
            test(&port).await.unwrap();
        }
    });

    // Spawn a task to make time ticks.
    let tick_handle = tokio::spawn(async move {
        loop {
            sleep(Duration::from_millis(1000)).await;
            println!("Tick!");
        }
    });

    // Wait for task to complete.
    tokio::select! {
        _ = work_handle => {
            info!("Work task completed.");
        },
        _ = tick_handle => {
            println!("Tick task completed.");
        }
    }
    Ok(())
}

Run under WSL/Debian it fails to find my serial adapter.

$ echo  hello > /dev/ttyS3       # This works.
$ RUST_LOG=debug cargo run /dev/ttyS3
    Finished dev [unoptimized + debuginfo] target(s) in 0.26s
     Running `target/debug/rust-serial-port /dev/ttyS3`
Using port: /dev/ttyS3
No ports found.
[2020-10-27T14:03:01Z ERROR rust_serial_port::serial] Custom { kind: Other, error: "Not a typewriter" }
Tick!

Googling around suggests serial ports under the WSL have ioctls missing so many thing do not work.

OK, I thought, no prob, I can build it for Windows and run it from the command prompt. That does at least find my serial adapter but then the tokio task panics when trying to open it:

>echo hello > COM3          #This works,
>cargo run com3
    Finished dev [unoptimized + debuginfo] target(s) in 0.19s
     Running `target\debug\rust-serial-port.exe com3`
Value for config: default.conf
Using port: com3
No verbose info
Found 3 ports:
  COM5
    Type: Unknown
  COM4
    Type: Unknown
  COM3
    Type: USB
    VID:0403 PID:6001
     Serial Number: AD0JL5RTA
      Manufacturer: FTDI
           Product: USB Serial Port (COM3)
thread 'tokio-runtime-worker' panicked at 'there is no reactor running, must be called from the context of Tokio runtime', C:\Users\zicog\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.22\src\io\driver\mod.rs:202:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
[2020-10-27T14:06:29Z INFO  rust_serial_port] work task completed.

Any suggestions?

thread 'tokio-runtime-worker' panicked at 'there is no reactor running, must be called from the context of Tokio runtime', C:\Users\zicog\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.22\src\io\driver\mod.rs:202:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Did you by any chance mix up Tokio 0.2 and 0.3 libraries?

Not as far as I can tell. My Cargo.toml contains only:

[dependencies]
tokio = { version = "0.3", features = ["full"] }
tokio-serial = "4.3.3"
serialport = "3.3.0"
anyhow = "1.0.33"
clap = "2.33.3"
log = "0.4"
env_logger = "0.8.1"

Looking at docs.rs it seems that tokio-serial uses Tokio 0.2.

1 Like

Hmm...

OK I down graded to tokio tokio "0.2"

Which broke my sleeps.

Which I give up trying to fix as there seem to be a dozen versions in different crates with different names, "sleep", "delay_for"...

So I removed the sleep and just run it:

>cargo run com3
    Finished dev [unoptimized + debuginfo] target(s) in 0.13s
     Running `target\debug\rust-serial-port.exe com3`
Value for config: default.conf
Using port: com3
No verbose info
Found 3 ports:
  COM5
    Type: Unknown
  COM4
    Type: Unknown
  COM3
    Type: USB
    VID:0403 PID:6001
     Serial Number: AD0JL5RTA
      Manufacturer: FTDI
           Product: USB Serial Port (COM3)
Serial open
Waiting on read...

Yay, serial open !

This has been yet another tokio tear my hair out day. Compounded by the fact that one of the two USB adapters with Prolific chips in is recognized but does not open!

Now, how do I get my sleeps back?

How are you gleaning from any docs, which crate versions work with what?

Every time I start a new tokio project I end up chasing round in circles trying to find a matched set of versions to get what I need done.

Still no sign of life on the WSL side. Ah well.

Thanks.

Sleep was called delay_for in Tokio 0.2. You can see the version by going to the top of the page and hovering the thing with the drop down. There's a list of dependencies in that drop down.

1 Like

Ah thanks.

I would be neat if these crucial details were on the crates.io pages. Along with the feature flags you need etc.

I tried delay_for already. Didn't work. Will try harder.

What will I be missing by using tokio 0.2 instead of 0.3?

Well delay_for should work. What's wrong with it? As for the difference, they are relatively few from the user's perspective. The release exists because there were a few apis we wanted to fix with 1.0, and 0.3 let's us try them out before we commit long term with Tokio 1.0.

1 Like

Nothing wrong with delay_for(). Now that I have all my dependencies sorted out everything starts to work, on Windows at least.

Under the WSL serialport is now working.

Which is a shame because serial ports work fine in the WSL with node.js:

const SerialPort = require('serialport')
const port = new SerialPort('/dev/ttyS3')

// Open errors will be emitted as an error event
port.on('error', function(err) {
  console.log('Error: ', err.message)
})

SerialPort.list().then(ports => {
  console.log('Serial ports:');
  ports.forEach(function(port) {
    console.log(port.path);
    console.log(port.pnpId);
    console.log(port.manufacturer);
  });
});

setInterval(function () {
  port.write('Hello', function(err) {
    if (err) {
      return console.log('Error on write: ', err.message)
    }
    console.log('message written')
  })
    console.log('Tick!');
}, 1000);
$ node index.js
Serial ports: []
Tick!
message written

Well, except the list method.

Thangs again.

Turns out the fact that serialport does not work in the WSL is a know issue: https://gitlab.com/susurrus/serialport-rs/-/issues/52

Also turns out that having any USB serial adapter plugged into this Win 10 PC causes the mouse to stall and jitter. Nothing to do with Rust of course.

Are they ever going to get this USB mess to work properly?

1 Like

Serialport-rs dev here. I just submitted