serial-rs
serial-rs copied to clipboard
Custom baud rate
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 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 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!
Also, a complete solution needs to deal with getting the custom baud rate from read_settings() as well.
Should be fixed in 42e2bcf
@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:
-
Define
TCGETS2
,TCSETS2
,TCSETSW2
, andTCSETSF2
in the ioctl crate. -
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
forCBAUDEX
, maybe it can be aconst
that's local to this crate. -
As for setting the
c_ispeed
andc_ospeed
fields, the changes totermios
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.
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.
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
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"