Seriaport crate: read from Arduino serial.println()

Hi! I'm making a fader controller with Arduino. When I move the fader I send via serial.println() a comma string separated values, like "18,42". In another C++ project I used Qt with QSerialPort which has readLine() methods that take care of all. Reading on the web I found someone that suggests using the std::io::BufReader, but it complains with the timeout of the serialport crate.
Using the serialport crate, how can I read each line received from Arduino?
Thanks!

Please show actual code. It's not possible to debug plaintext.

From Arduino I send a string message via serial that contains a comma-separated values:

void transmit(int v1, int v2) {
  String message = (String) v1 + "," + (String) v2;
  Serial.println(message);
  Serial.flush();
}

then from Rust I would like to read this message. Using serialport crate I used read() method passing a buffer:

let mut buf: [u8; 2] = [0; 2];
let serial_read = serial.read(buf.as_mut_slice());
match serial_read {
  Ok(2) => dbg!(buf),
  Err(e) => dbg!(e),
}

but the numbers received are not correct, I expect to receive the pin number 18 and a value (for example "18,21\r\n") but I get a different output:

[src\main.rs:126] buf = [
    49,
    56,
]

I'm aware that I'm trying to read my message with the wrong approach, but without a read-line function from the serialport crate I dunno how to correctly read and convert my message.

Thanks.

Your dbg! is printing the decimal value of the bytes received, 49 and 56. They are the ASCII characters for "1" and "8". So you have the beginning of the string you sent, "18". See a table of ASCII character codes here: https://www.asciitable.com

You will need to. make a valid String from those bytes. Something like:

str::from_utf8(&buf).unwrap();

But note: serial.read(...) knows nothing of the lines you are receiving. It only receives some bytes, which may be part of a line or multiple lines.

You can read about how to read lines from a serial port here: serial port - How to use read_line function with Rust's serialport crate - Stack Overflow

2 Likes

The serialport crate just uses the standard library Read trait for reading from a serial port, so all the tools in the standard library for reading in the right format are available. In particular, you can get a read_line() function by wrapping it in a BufReader.

Thanks @ZiCog now with str::from_utf8(&buf).unwrap(); I can cast my ASCII to readable chars.

@jameseb7 I tried using read_line() from BufReader:

let mut port = serialport::new(&selected_port_name, 115_200)
        .timeout(Duration::from_millis(100))
        .open()
        .unwrap();
port.set_flow_control(serialport::FlowControl::Hardware).unwrap();
loop {
  let mut reader = BufReader::new(port);
  let mut my_str = String::new();
  let serial_read = reader.read_line(&mut my_str).unwrap();
  if serial_read > 0 {
      dbg!(my_str);
      }else{
  break;
}
}

but it complains after the timeout value (100ms):

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: TimedOut, error: "Operation timed out" }',

I tried to change from 100ms to 0, but nothing appears.

If I set 1000ms and I move my potentiometer within this time, I get every second the correct reading, but when I stop moving it complains again.

Ok, I found a solution. I can avoid unwrapping and panicking the main function in case of timeout. So I did:

let mut port = serialport::new(&selected_port_name, 115_200)
        .timeout(Duration::from_millis(1))
        .open()
        .unwrap();
port.set_flow_control(serialport::FlowControl::Hardware)
    .unwrap();

let mut reader = BufReader::new(port);
let mut my_str = String::new();
loop {
    let read_line = reader.read_line(&mut my_str);
    match read_line {
        Ok(_n) => {
            dbg!(&my_str);
            my_str.clear();
        },
        Err(_e) => {}
        }
    }
}

so here I set 1ms timeout and within the loop I constantly read my buffer avoiding the timeout error.

For a better solution, I will read the Kind of error and avoid only the timeout one.

Is there any particular reason you want a timeout there? Try just not setting a timeout.

Tried, but values doesn't appear..

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.