serial-rs icon indicating copy to clipboard operation
serial-rs copied to clipboard

Custom baud rate

Open mbr opened this issue 7 years ago • 7 comments

This pull request contains code that allows setting custom bit rates on Linux, which is very useful for handling strange or proprietary protocols.

For this to work, first https://github.com/dcuddeback/termios-rs/pull/8 needs to be reviewed and merged, then the dependency bumped (travis CI will fail until this is done, sorry).

Afterwards, a different ioctl will be used to set the speed. TCSET2 respects custom baud rates.

mbr avatar Mar 03 '17 17:03 mbr

@mbr Interesting. I've never seen this method of setting a custom baud rate on Linux. Usually, I see the TIOCSSERIAL/TIOCGSERIAL ioctls, which is what I was planning to use when I got around to implementing this. Any reason to prefer this approach over the TIOCSSERIAL ioctl?

Also, a complete solution needs to deal with getting the custom baud rate from read_settings() as well.

dcuddeback avatar Mar 05 '17 04:03 dcuddeback

@dcuddeback That interface is deprecated. It's a bit confusing, because the termios-rs crate uses a confusing label for the datastructure (see https://github.com/dcuddeback/termios-rs/pull/8)

I found an blog post here: https://www.downtowndougbrown.com/2013/11/linux-custom-serial-baud-rates/ , which explains it better than I ever could!

mbr avatar Mar 05 '17 11:03 mbr

Also, a complete solution needs to deal with getting the custom baud rate from read_settings() as well.

Should be fixed in 42e2bcf

mbr avatar Mar 05 '17 16:03 mbr

@mbr Thanks for the link. That was very informative. Sounds like TCSETS2 is the way to go. I have some more reading to do on this, but I have to go out of town in a little bit. So far, I've confirmed that glibc still uses the old TCSETS. TCSETS2 isn't referenced anywhere in glibc master, so using the ioctl directly is probably the only way to do this, which is fine.

My thoughts at the moment on how to get this ready are:

  1. Define TCGETS2, TCSETS2, TCSETSW2, and TCSETSF2 in the ioctl crate.

  2. I'm not sure about what to do with BOTHER. That doesn't seem to be exposed by #include <termios.h>, but I haven't verified that. If that's the case, I'm not sure if it belongs in the termios crate. If it's guaranteed to always be a #define for CBAUDEX, maybe it can be a const that's local to this crate.

  3. As for setting the c_ispeed and c_ospeed fields, the changes to termios should be consistent with that crate's goals of providing a portable interface while keeping OS-specific extensions obivous: http://dcuddeback.github.io/termios-rs/termios/#portability:

    Programs that depend on OS-specific functionality must explicity opt-in.

    For the Termios struct, that means that the public fields are only those defined in POSIX. There are still ways to make those fields accessible, though. The technique I see most (e.g., in the standard library) is to define extension traits for OS-specific functionality. In this case, an extension trait for Linux could provide {set,get}_{i,o}speed() methods.

That's all the time I have to look at this for now. Hope that helps.

dcuddeback avatar Mar 05 '17 17:03 dcuddeback

Well, I can't do more at the moment, other than the PRs and issues in serial-rs, termio-rs and ioctl-rs that I have made so far (I would recommend starting with the ioctl and termio ones, those are real bugs, not feature requests =)).

On the upside, investigating and fixing these issues here will probably get the library a lot of the way towards implementing #37.

mbr avatar Mar 05 '17 22:03 mbr

I actually made changes to support custom baud rates in linux more than a year ago, but forgot to make a pull request. I reapplied the changes to current master, here is the commit: https://github.com/marjakm/serial-rs/commit/32c63c47b65deec1ad5d651b20db50172ff71b38

it uses my fork of termios-rs in which I have added tgets2, tsets2 and termios2 https://github.com/marjakm/termios-rs

Everything added should only be available in linux without changing the api. I haven't tested the updated version much, but the version from more than a year ago worked well, at least on beaglebone black.

Don't have time right now to make pull requests, but will do it next week if these patches seem ok

marjakm avatar Sep 01 '17 14:09 marjakm

Using the custom baudrate is still pain. I try to use the reading serialport using this lib with 10000 baudrates.

I do it like that

extern crate sbus;
extern crate serial;

use std::io::prelude::*;
use serial::prelude::*;

/*  Setting for serial port before run it */
const SETTINGS: serial::PortSettings = serial::PortSettings {
    baud_rate:    serial::BaudOther(100000), // baud rate
    char_size:    serial::Bits8, // char size of serial port (unit: bits)
    parity:       serial::ParityEven, // Parity of serial port
    stop_bits:    serial::Stop2, // stop bits
    flow_control: serial::FlowNone, // flow mode 
};
/* Main function */
fn main() {
    println!("opening port...");
    let mut port = serial::open("/dev/ttyACM0").unwrap(); // open serial port
    port.configure(&SETTINGS).unwrap();// setting serial port before read information or bytes (Notice: this variable can use a constant struct)
    let mut buf:[u8; 8] = [0; 8]; // buffer of one arrays...
    /* read bytes in infitite loop */
    loop {
        port.read(&mut buf[..]).unwrap(); // read bytes for serial port device 
        println!("reading bytes : {}", buf[0]); // print bytes in ternimal 
      
       

}


}

The program run is gives me the error InvalidValue error (Full log):

   Compiling readuart v0.1.0 (/home/bestosinworldnot/readuart)
    Finished dev [unoptimized + debuginfo] target(s) in 0.25s
     Running `target/debug/readuart`
opening port...
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { kind: InvalidInput, description: "Invalid argument" }', src/main.rs:28:31
stack backtrace:
   0:     0x55aca2fb15e5 - backtrace::backtrace::libunwind::trace::h14d338b30b3ea0a7
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.46/src/backtrace/libunwind.rs:86
   1:     0x55aca2fb15e5 - backtrace::backtrace::trace_unsynchronized::h73ea91d74a3fd67f
                               at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.46/src/backtrace/mod.rs:66
   2:     0x55aca2fb15e5 - std::sys_common::backtrace::_print_fmt::hd42948c952866e12
                               at src/libstd/sys_common/backtrace.rs:78
   3:     0x55aca2fb15e5 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::ha8f928866ff7571e
                               at src/libstd/sys_common/backtrace.rs:59
   4:     0x55aca2fce47c - core::fmt::write::he0c1e5f7426d2718
                               at src/libcore/fmt/mod.rs:1076
   5:     0x55aca2faf9d2 - std::io::Write::write_fmt::hf3afc6cfd57d0033
                               at src/libstd/io/mod.rs:1537
   6:     0x55aca2fb3a20 - std::sys_common::backtrace::_print::hfc0110703f3696fd
                               at src/libstd/sys_common/backtrace.rs:62
   7:     0x55aca2fb3a20 - std::sys_common::backtrace::print::h3f77c6990ddfaa22
                               at src/libstd/sys_common/backtrace.rs:49
   8:     0x55aca2fb3a20 - std::panicking::default_hook::{{closure}}::heae49580a8d62d75
                               at src/libstd/panicking.rs:198
   9:     0x55aca2fb376c - std::panicking::default_hook::hecc34e3f729e213c
                               at src/libstd/panicking.rs:217
  10:     0x55aca2fb4063 - std::panicking::rust_panic_with_hook::he82f5d0644692441
                               at src/libstd/panicking.rs:526
  11:     0x55aca2fb3c5b - rust_begin_unwind
                               at src/libstd/panicking.rs:437
  12:     0x55aca2fcd881 - core::panicking::panic_fmt::h09c929f06bb87c98
                               at src/libcore/panicking.rs:85
  13:     0x55aca2fcd6a3 - core::option::expect_none_failed::h188f17af6c9f404b
                               at src/libcore/option.rs:1269
  14:     0x55aca2fa17fa - core::result::Result<T,E>::unwrap::h2b57d26a2c337822
                               at /home/bestosinworldnot/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/result.rs:1005
  15:     0x55aca2fa0f8c - readuart::main::h324f14bdc387d56d
                               at src/main.rs:28
  16:     0x55aca2fa144b - std::rt::lang_start::{{closure}}::hd9fd8f1b710851f3
                               at /home/bestosinworldnot/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:67
  17:     0x55aca2fb4433 - std::rt::lang_start_internal::{{closure}}::h5d3ea623498f5f43
                               at src/libstd/rt.rs:52
  18:     0x55aca2fb4433 - std::panicking::try::do_call::hac65e71be769a440
                               at src/libstd/panicking.rs:348
  19:     0x55aca2fb4433 - std::panicking::try::hd4706e264bcf6712
                               at src/libstd/panicking.rs:325
  20:     0x55aca2fb4433 - std::panic::catch_unwind::h948a0fb4a8b3ee82
                               at src/libstd/panic.rs:394
  21:     0x55aca2fb4433 - std::rt::lang_start_internal::h72cc068ed2d0ac53
                               at src/libstd/rt.rs:51
  22:     0x55aca2fa1427 - std::rt::lang_start::hb4ad2f485bd2bd3a
                               at /home/bestosinworldnot/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:67
  23:     0x55aca2fa10fa - main
  24:     0x7fdd80154b97 - __libc_start_main
  25:     0x55aca2fa0dba - _start
  26:                0x0 - <unknown>

The 100000 is working fine. But not 10000. Code runned on Ubuntu Linux verisons: Linux kernel : 5.4.0-51-generic Rustc verison : rustc 1.46.0 (04488afe3 2020-08-24) Cargo version: cargo 1.46.0 (149022b1d 2020-07-17) serial-unix = "0.4.0" serial-core = "0.4.0" serial = "0.4.0" libc = "0.2.79"

azaslavskis avatar Oct 26 '20 23:10 azaslavskis