How to connect to a serial device

Hello,

I'm pretty new to Rust and I thought I gonna start with some things I once coded in other languages. To get started I chose a small program. I just want to connect to a UART device write and read to it, but I cannot get it to work. I use https://crates.io/crates/serialport library. This is my code:

use std::time::Duration;
use std::io::Write;

fn main() {
    let mut port = serialport::new("/dev/ttys002", 115_200).open_native().expect("Failed to open port").expect("Failed to open.");
    let output = "This is a test. This is only a test.".as_bytes();
    port.write(output).expect("Write failed!");   
}

I mean it is a simple example but I keep getting the following error:

thread 'main' panicked at 'Failed to open port: Error { kind: Unknown, description: "Not a typewriter" }', src/main.rs:5:75

Does /dev/ttys002 exist? Do you have permission to access it?

Yep, that's the port socat opened up.

What OS are you on? Is it Windows Subsystem for Linux by any chance? It loooks like WSL is unsupported at the moment and people get the same "not a typewriter" error: Windows Subsystem for Linux (WSL) Port '/dev/ttySX' not available: Not a typewriter (#52) · Issues · Bryant / serialport-rs · GitLab

2 Likes

MacOS BigSur Version 11.1 (20C69) and the latest Rust version:

rustc 1.47.0

:thinking: I think I gonna give it a go on Ubuntu it should be possible to get such a small piece of code running, hopefully :slightly_smiling_face:

That's definitely a solid idea. Apple have been doing some pretty funny business around revoking permissions of files located in system directories. I wouldn't be surprised if Big Sur was programmed to silently deny TTY connections with a misleading error message to everything except their own apps.

I am on Big Sur myself, so I'll try to reproduce the error on my own machine.

I don't think this is the underlying problem but latest stable Rust is 1.49.0, you might want to run rustup update stable.

1 Like

that does not work:

info: syncing channel updates for 'stable-x86_64-apple-darwin'

stable-x86_64-apple-darwin unchanged - rustc 1.49.0 (e1884a8e3 2020-12-29)

info: checking for self-updates

$rustc --version
 >rustc 1.47.0

I guess I gonna start with something else.

Seems like there's another rustc binary somewhere on your PATH that's getting in the way of the rustup-managed version. What is the output of

$ which rustc

on your machine? The rustup version should (?) be located at ~/.cargo/bin/rustc.

I installed Rust via Homebrew:

/usr/local/bin/rustc

Should I start over?

Ah, okay. You should definitely have either homebrew Rust or rustup Rust on your machine, not both. I recommend rustup, which will always have the latest releases; there might be (and from what you've said it sounds like there is) a significant lag in homebrew's packaging.

1 Like

I see, This idea came to my mind after I saw your post. I tried it via brew upgrade rust and got this:

Error: homebrew-cask is a shallow clone. To `brew update` first run:
git -C "/usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask" fetch --unshallow
This restriction has been made on GitHub's request because updating shallow
clones is an extremely expensive operation due to the tree layout and traffic of
Homebrew/homebrew-cask. We don't do this for you automatically to avoid
repeatedly performing an expensive unshallow operation in CI systems (which
should instead be fixed to not use shallow clones). Sorry for the inconvenience!
Warning: rust 1.47.0 already installed

Ok, I uninstall the homebrerw version and reinstall

rustup
1 Like

:rage: it still does not work but many thanks for helping me getting the right Rust installation.

1 Like

Can you write to the device using other programms, e.g. cat? If that does not work, the problem is probably not in your rust code.
(cat "This is a test. This is only a test." > /dev/ttys002)

that works fine.

If you're still having trouble I'd suggest opening an issue on the serialport repo; the maintainers can probably give you better debugging guidance.

1 Like

It took a while but it seems serialport does not work with virtual ports. I finally have access to the LoRa module and now I can write and receive data. Which brings me to my next question.
I send an AT command and the expected value should be AT, OK. What I get is 1. I mean that's the right value for Vec<u8> and usize as return value of the read() function.

let mut serial_buf: Vec<u8> = vec![0; 32];
let message = port.read(serial_buf.as_mut_slice()).expect("Found no data!"); println!("{}", message);

But how can I convert this value to utf-8?

What do you mean by "converting to UTF-8"? Either what you have is already UTF-8, in which case you can convert it to a string or an &str using one of the suitable functions (str::from_utf8(), String::from_utf8()), or what you have is not yet UTF-8, in which case you have to consider what the encoding format and the semantics of the data read into the buffer is, then possibly output a string based on its contents.

Do you mean that serial_buf is supposed to contain the string AT, OK? If so, then 1 is not the right return value, because read() returns the number of bytes read, and the string AT, OK is definitely not 1 byte long. This might happen for a number of reasons:

  • Maybe the serial port just couldn't provide more bytes at a time. Unlikely, but possible. In this case, you should probably be using read_to_end() instead of plain read(). There's no guarantee that read() can or will read all available data at once.
  • Or perhaps what you get back isn't a literal string, only a single-byte status code that means "OK". In this case, you should read up on the relevant documentation to be able to convert this status code to a human-readable message, if that's what you need.

Ok thanks , I gonna try read_to_end()