Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom baud rate #42

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Custom baud rate #42

wants to merge 5 commits into from

Conversation

mbr
Copy link

@mbr mbr commented Mar 3, 2017

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 dcuddeback/termios-rs#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 added 2 commits March 3, 2017 18:22
The TCSETS2 uses the more modern ioctl that supports setting custom
bitrates. The only loss here is the ability to specify
`optional_actions`; compare
https://fossies.org/dox/glibc-2.25/sysdeps_2unix_2bsd_2tcsetattr_8c_source.html

As these are not used anyway, this is a net gain in functionality.

Gated through conditional compilation to run only on Linux.
With support of the `TCSETS2` ioctl, custom bitrates are now possible on
Linux. This commit adds support for these.
@dcuddeback
Copy link
Owner

@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.

@mbr
Copy link
Author

mbr commented Mar 5, 2017

@dcuddeback That interface is deprecated. It's a bit confusing, because the termios-rs crate uses a confusing label for the datastructure (see dcuddeback/termios-rs#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
Copy link
Author

mbr commented Mar 5, 2017

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

Should be fixed in 42e2bcf

@dcuddeback
Copy link
Owner

@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.

@mbr
Copy link
Author

mbr commented Mar 5, 2017

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.

@marjakm
Copy link

marjakm commented Sep 1, 2017

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:
marjakm@32c63c4

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

@azaslavskis
Copy link

azaslavskis commented Oct 26, 2020

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"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants