de-vri-es / serial2-rs

Cross platform serial ports for Rust
Other
41 stars 10 forks source link

setting configuration does NOT work #5

Closed Sieyalixnet closed 1 year ago

Sieyalixnet commented 1 year ago

Environment: apple M2 and rust edition = "2021".

I used many method to set the Settings including implement the apply_to_settings trait, get the Settings from a port and then modify it by using like set_char_size and then apply it by set_configuration. And then I use get_configuration to check it, but the settings do not change even I used set_configuration to modified it. I modify most of settings like baud rate, char size and stop bits..., but it ONLY works when I was modifying the baud rate. It do not throw an exception when I use set_configuration.

de-vri-es commented 1 year ago

Could you tell me a bit more? Which serial port device are you trying to change the settings for? What is the name of the device on the system, and what is the name according to the vendor?

de-vri-es commented 1 year ago

And could you share a minimum example showing that the settings are not updated as expected without raising an error?

Sieyalixnet commented 1 year ago

I am sorry, here's the code

fn main() {
    let mut port = SerialPort::open("/dev/cu.usbserial-0001", 115200).unwrap();
    let mut settings1 = port.get_configuration().unwrap().clone();
    println!(
        "{:?},{:?},{:?},{:?},{:?}",
        settings1.get_char_size(),
        settings1.get_flow_control(),
        settings1.get_parity(),
        settings1.get_stop_bits(),
        settings1.get_baud_rate()
    );
    settings1.set_baud_rate(9600);
    settings1.set_char_size(serial2::CharSize::Bits5);
    settings1.set_flow_control(serial2::FlowControl::XonXoff);
    port.set_configuration(&settings1);
    let mut settings2 = port.get_configuration().unwrap().clone();
    println!(
        "{:?},{:?},{:?},{:?},{:?}",
        settings2.get_char_size(),
        settings2.get_flow_control(),
        settings2.get_parity(),
        settings2.get_stop_bits(),
        settings2.get_baud_rate()
    );
}

in terminal, the output is

Ok(Bits8),Ok(None),Ok(None),Ok(One),Ok(115200)
Ok(Bits8),Ok(None),Ok(None),Ok(One),Ok(9600)

I changed the library to serialport, but it works.

de-vri-es commented 1 year ago

Hmm, you're not checking for errors when setting the configuration.

Could you try that to see if it reports an error?

 port.set_configuration(&settings1).unwrap();
Sieyalixnet commented 1 year ago

If I set "serial2::FlowControl::RtsCts" for flow control, it will crash. So here I try to set other settings.

However it will success, but still perform like above:

fn main() {
    let mut port = SerialPort::open("/dev/cu.Bluetooth-Incoming-Port", 115200).unwrap();// I have not USB serial device now.
    let mut settings1 = port.get_configuration().unwrap().clone();
    println!(
        "{:?},{:?},{:?},{:?},{:?}",
        settings1.get_char_size(),
        settings1.get_flow_control(),
        settings1.get_parity(),
        settings1.get_stop_bits(),
        settings1.get_baud_rate()
    );
    settings1.set_baud_rate(9600).unwrap();
    settings1.set_char_size(serial2::CharSize::Bits5);
    settings1.set_parity(serial2::Parity::Even);
    settings1.set_stop_bits(serial2::StopBits::Two);
    //settings1.set_flow_control(serial2::FlowControl::RtsCts);
    port.set_configuration(&settings1).unwrap();//!!!! I added unwrap() here
    let mut settings2 = port.get_configuration().unwrap().clone();
    println!(
        "{:?},{:?},{:?},{:?},{:?}",
        settings2.get_char_size(),
        settings2.get_flow_control(),
        settings2.get_parity(),
        settings2.get_stop_bits(),
        settings2.get_baud_rate()
    );
}

In terminal :

Ok(Bits8),Ok(None),Ok(None),Ok(One),Ok(115200)
Ok(Bits8),Ok(None),Ok(None),Ok(Two),Ok(9600)

Even i added unwrap, it was successful to set the configuration. but the char size and parity didn't change.

DanielJoyce commented 1 year ago

Not all hardware is required to support all formats. It may be baudot code is not supported, its super old and very little used.

If its not supported though, I'd expect the set_configuration to return an error.?

DanielJoyce commented 1 year ago

Looking, it appears set_on_file uses an ioctl on linux instead of tcsetattr. Any reason why?

Also it says it allows the buffer to drain before applying settings.

DanielJoyce commented 1 year ago

From here:

https://manpages.debian.org/testing/manpages-dev/ioctl_tty.2.en.html

The following four ioctls, added in Linux 2.6.20, are just like TCGETS, TCSETS, TCSETSW, TCSETSF, except that they take a struct termios2 * instead of a struct termios *. If the structure member c_cflag contains the flag BOTHER, then the baud rate is stored in the structure members c_ispeed and c_ospeed as integer values. These ioctls are not supported on all architectures.

TCGETS2 | struct termios2 *argp -- | -- TCSETS2 | const struct termios2 *argp TCSETSW2 | const struct termios2 *argp TCSETSF2 | const struct termios2 *argp
Are we using a termios2 struct for tcsetsw2?
DanielJoyce commented 1 year ago

Okay, it looks like termios2 is being used.

de-vri-es commented 1 year ago

Yeah, but this issue is about macOS, so it's somewhat different.

One annoying thing: the underlying syscall for setting TTY settings reports success if it applied any of the settings, not if it applied all of the settings.

de-vri-es commented 1 year ago

I don't have a macOS device, so I can't really debug this myself.

What would help is to try and set each setting one at a time, and see if we get a failure then:

fn main() {
    let mut port = SerialPort::open("/dev/cu.Bluetooth-Incoming-Port", 115200).unwrap();
    let mut settings = port.get_configuration().unwrap();
    print_settings(&settings);

    settings.set_baud_rate(9600).unwrap();
    port.set_configuration(&settings).unwrap();
    let mut setting = port.get_configuration().unwrap();
    print_settings(&settings);

    settings.set_char_size(serial2::CharSize::Bits5);
    port.set_configuration(&settings).unwrap();
    let mut setting = port.get_configuration().unwrap();
    print_settings(&settings);

    settings.set_parity(serial2::Parity::Even);
    port.set_configuration(&settings).unwrap();
    let mut setting = port.get_configuration().unwrap();
    print_settings(&settings);

    settings.set_stop_bits(serial2::StopBits::Two);
    port.set_configuration(&settings).unwrap();
    let mut setting = port.get_configuration().unwrap();
    print_settings(&settings);

    // settings1.set_flow_control(serial2::FlowControl::RtsCts);
    // port.set_configuration(&settings).unwrap();
    // let mut setting = port.get_configuration().unwrap();
}

fn print_settings(settings: &serial2::Settings) {
    println!(
        "{:?},{:?},{:?},{:?},{:?}",
        settings.get_char_size(),
        settings.get_flow_control(),
        settings.get_parity(),
        settings.get_stop_bits(),
        settings.get_baud_rate()
    );
}
Sieyalixnet commented 1 year ago

Setting flow control to RtsCts will be crashed, but it is ok if I set XonXoff. So I add this setting. Here's the code:

use serial2::SerialPort;

fn main() {
    let mut port = SerialPort::open("/dev/cu.usbserial-110", 115200).unwrap();
    let mut settings = port.get_configuration().unwrap();
    print_settings(&settings);

    settings.set_baud_rate(9600).unwrap();
    port.set_configuration(&settings).unwrap();
    let mut setting = port.get_configuration().unwrap();
    print_settings(&settings);

    settings.set_char_size(serial2::CharSize::Bits5);
    port.set_configuration(&settings).unwrap();
    let mut setting = port.get_configuration().unwrap();
    print_settings(&settings);

    settings.set_parity(serial2::Parity::Even);
    port.set_configuration(&settings).unwrap();
    let mut setting = port.get_configuration().unwrap();
    print_settings(&settings);

    settings.set_stop_bits(serial2::StopBits::Two);
    port.set_configuration(&settings).unwrap();
    let mut setting = port.get_configuration().unwrap();
    print_settings(&settings);

    settings.set_flow_control(serial2::FlowControl::XonXoff);
    port.set_configuration(&settings).unwrap();
    let mut setting = port.get_configuration().unwrap();
}

fn print_settings(settings: &serial2::Settings) {
    println!(
        "{:?},{:?},{:?},{:?},{:?}",
        settings.get_char_size(),
        settings.get_flow_control(),
        settings.get_parity(),
        settings.get_stop_bits(),
        settings.get_baud_rate()
    );
}

Here's the output:

Ok(Bits8),Ok(None),Ok(None),Ok(One),Ok(115200)
Ok(Bits8),Ok(None),Ok(None),Ok(One),Ok(9600)
Ok(Bits5),Ok(None),Ok(None),Ok(One),Ok(9600)
Ok(Bits5),Ok(None),Ok(Odd),Ok(One),Ok(9600)
Ok(Bits5),Ok(None),Ok(Odd),Ok(Two),Ok(9600)

It is quite strange in setting the flow control and parity.

de-vri-es commented 1 year ago

Ah, I found a bug in reporting the parity setting. It was reporting Odd and Even flipped. Setting it did actually work though.

Released 0.1.10 and 0.2.1 with a fix.

Regarding flow control, my guess is that the adapter doesn't support it? Or have you been able to get hardware flow control to work with other libraries?

Also, thank you for the reports, they are very useful!

Sieyalixnet commented 1 year ago

Yes, the flow control can not be set maybe caused by the hardware. I try to set flow control by another library named serialport, it also doesn't work.(But in that library, both of them (FlowControl::Hardware, FlowControl::Software) can not be set.)