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

Resolve Mac OS setting Prolific Technology adapter #194

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

skmagiik
Copy link

@skmagiik skmagiik commented Jun 3, 2024

This resolves an issue where the baudrate would not be recognized on Mac OS.
fixes #190
The adapter details for the faulty adapter are below:

Device Descriptor
Descriptor Version Number: 0x0200
Device Class: 0 (Composite)
Device Subclass: 0
Device Protocol: 0
Device MaxPacketSize: 64
Device VendorID/ProductID: 0x067B/0x2303 (unknown vendor)
Device Version Number: 0x0300
Number of Configurations: 1
Manufacturer String: 1 "Prolific Technology Inc."
Product String: 2 "USB-Serial Controller"
Serial Number String: 0 (none)

I tested with other adapters (mostly FTDI adapters) and baudrates and this has not provided me with any adverse side effects.

This resolves an issue where the baudrate would not be
recognized on Mac OS. The adapter details for the faulty adapter are
below:

Device Descriptor
        Descriptor Version Number:   0x0200
        Device Class:   0   (Composite)
        Device Subclass:   0
        Device Protocol:   0
        Device MaxPacketSize:   64
        Device VendorID/ProductID:   0x067B/0x2303   (unknown vendor)
        Device Version Number:   0x0300
        Number of Configurations:   1
        Manufacturer String:   1 "Prolific Technology Inc."
        Product String:   2 "USB-Serial Controller"
        Serial Number String:   0 (none)
@pmnxis
Copy link

pmnxis commented Feb 4, 2025

I think this issue is very important...
Is there any news on this?

pmnxis added a commit to pmnxis/egui_term that referenced this pull request Feb 5, 2025
…ort-rs and mio-serial.

The problem comes with their baudrate fd mechanism is different compare to all others in macOS.

Related issue : serialport/serialport-rs#194
@sirhcel
Copy link
Contributor

sirhcel commented Feb 7, 2025

Thank you for this PR @skmagiik! I finally managed to get some PL2303 devices and give the proposed changes a spin (on top of the current master (with 7ee2b5a/sirhcel/pr-194-prolific-baud).

For me, just running the tests with a pair of FT232H Mini module and a PL2303 cable fails at several points:

# The PL2303 cable
$ export SERIALPORT_TEST_PORT_1=[...]
# The FT2232H Mini dongle
$ export SERIALPORT_TEST_PORT_2=[...]
$ cargo test --no-fail-fast
[...]
     Running tests/test_baudrate.rs (target/debug/deps/test_baudrate-2cc756afd9f0c4cf)

running 27 tests
test builder::test_non_standard_baud_rate_fails_where_not_supported::case_1 ... ignored
test builder::test_non_standard_baud_rate_fails_where_not_supported::case_2 ... ignored
test builder::test_non_standard_baud_rate_fails_where_not_supported::case_3 ... ignored
test builder::test_non_standard_baud_rate_succeeds_where_supported::case_1 ... FAILED
test builder::test_non_standard_baud_rate_succeeds_where_supported::case_2 ... FAILED
test builder::test_non_standard_baud_rate_succeeds_where_supported::case_3 ... FAILED
test builder::test_standard_baud_rate::case_1 ... ok
test builder::test_standard_baud_rate::case_2 ... ok
test builder::test_standard_baud_rate::case_3 ... ok
test new::test_non_standard_baud_rate_fails_where_not_supported::case_1 ... ignored
test new::test_non_standard_baud_rate_fails_where_not_supported::case_2 ... ignored
test new::test_non_standard_baud_rate_fails_where_not_supported::case_3 ... ignored
test new::test_non_standard_baud_rate_succeeds_where_supported::case_1 ... FAILED
test new::test_non_standard_baud_rate_succeeds_where_supported::case_2 ... FAILED
test new::test_non_standard_baud_rate_succeeds_where_supported::case_3 ... FAILED
test new::test_standard_baud_rate::case_1 ... ok
test new::test_standard_baud_rate::case_2 ... ok
test new::test_standard_baud_rate::case_3 ... ok
test set_baud::test_non_standard_baud_rate_fails_where_not_supported::case_1 ... ignored
test set_baud::test_non_standard_baud_rate_fails_where_not_supported::case_2 ... ignored
test set_baud::test_non_standard_baud_rate_fails_where_not_supported::case_3 ... ignored
test set_baud::test_non_standard_baud_rate_succeeds_where_supported::case_1 ... ok
test set_baud::test_non_standard_baud_rate_succeeds_where_supported::case_2 ... ok
test set_baud::test_non_standard_baud_rate_succeeds_where_supported::case_3 ... ok
test set_baud::test_standard_baud_rate::case_1 ... ok
test set_baud::test_standard_baud_rate::case_2 ... ok
test set_baud::test_standard_baud_rate::case_3 ... ok

failures:

---- builder::test_non_standard_baud_rate_succeeds_where_supported::case_1 stdout ----
thread 'builder::test_non_standard_baud_rate_succeeds_where_supported::case_1' panicked at tests/test_baudrate.rs:86:14:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- builder::test_non_standard_baud_rate_succeeds_where_supported::case_2 stdout ----
thread 'builder::test_non_standard_baud_rate_succeeds_where_supported::case_2' panicked at tests/test_baudrate.rs:86:14:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }

---- builder::test_non_standard_baud_rate_succeeds_where_supported::case_3 stdout ----
thread 'builder::test_non_standard_baud_rate_succeeds_where_supported::case_3' panicked at tests/test_baudrate.rs:86:14:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }

---- new::test_non_standard_baud_rate_succeeds_where_supported::case_1 stdout ----
thread 'new::test_non_standard_baud_rate_succeeds_where_supported::case_1' panicked at tests/test_baudrate.rs:129:67:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }

---- new::test_non_standard_baud_rate_succeeds_where_supported::case_2 stdout ----
thread 'new::test_non_standard_baud_rate_succeeds_where_supported::case_2' panicked at tests/test_baudrate.rs:129:67:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }

---- new::test_non_standard_baud_rate_succeeds_where_supported::case_3 stdout ----
thread 'new::test_non_standard_baud_rate_succeeds_where_supported::case_3' panicked at tests/test_baudrate.rs:129:67:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }


failures:
    builder::test_non_standard_baud_rate_succeeds_where_supported::case_1
    builder::test_non_standard_baud_rate_succeeds_where_supported::case_2
    builder::test_non_standard_baud_rate_succeeds_where_supported::case_3
    new::test_non_standard_baud_rate_succeeds_where_supported::case_1
    new::test_non_standard_baud_rate_succeeds_where_supported::case_2
    new::test_non_standard_baud_rate_succeeds_where_supported::case_3

test result: FAILED. 12 passed; 6 failed; 9 ignored; 0 measured; 0 filtered out; finished in 36.62s
[...]
     Running tests/test_timeout.rs (target/debug/deps/test_timeout-366a4796eb1e7da8)

running 9 tests
test test_read_returns_available_data_before_timeout::case_1 ... FAILED
test test_read_returns_available_data_before_timeout::case_2 ... FAILED
test test_timeout_greater_zero::case_1 ... FAILED
test test_timeout_greater_zero::case_2 ... FAILED
test test_timeout_greater_zero::case_3 ... FAILED
test test_timeout_max ... FAILED
test test_timeout_zero::case_1 ... FAILED
test test_timeout_zero::case_2 ... FAILED
test test_timeout_zero::case_3 ... FAILED

failures:

---- test_read_returns_available_data_before_timeout::case_1 stdout ----
send: 1 bytes
send: 1 bytes
send: 1 bytes
send: 1 bytes
send: 1 bytes
send: 1 bytes
thread '<unnamed>' panicked at tests/test_timeout.rs:62:22:
unexpected error Err(Custom { kind: TimedOut, error: "Operation timed out" })
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'test_read_returns_available_data_before_timeout::case_1' panicked at tests/test_timeout.rs:88:28:
called `Result::unwrap()` on an `Err` value: Any { .. }

---- test_read_returns_available_data_before_timeout::case_2 stdout ----
send: 20 bytes
send: 20 bytes
send: 20 bytes
send: 19 bytes
thread '<unnamed>' panicked at tests/test_timeout.rs:62:22:
unexpected error Err(Custom { kind: TimedOut, error: "Operation timed out" })
thread 'test_read_returns_available_data_before_timeout::case_2' panicked at tests/test_timeout.rs:88:28:
called `Result::unwrap()` on an `Err` value: Any { .. }

---- test_timeout_greater_zero::case_1 stdout ----
thread 'test_timeout_greater_zero::case_1' panicked at tests/test_timeout.rs:167:43:
called `Result::unwrap()` on an `Err` value: Custom { kind: TimedOut, error: "Operation timed out" }

---- test_timeout_greater_zero::case_2 stdout ----
thread 'test_timeout_greater_zero::case_2' panicked at tests/test_timeout.rs:167:43:
called `Result::unwrap()` on an `Err` value: Custom { kind: TimedOut, error: "Operation timed out" }

---- test_timeout_greater_zero::case_3 stdout ----
thread 'test_timeout_greater_zero::case_3' panicked at tests/test_timeout.rs:167:43:
called `Result::unwrap()` on an `Err` value: Custom { kind: TimedOut, error: "Operation timed out" }

---- test_timeout_max stdout ----
thread 'test_timeout_max' panicked at /[...]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rstest-0.24.0/src/timeout.rs:26:49:
Timeout 15s expired

---- test_timeout_zero::case_1 stdout ----
thread 'test_timeout_zero::case_1' panicked at tests/test_timeout.rs:104:10:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Device or resource busy" }

---- test_timeout_zero::case_2 stdout ----
thread 'test_timeout_zero::case_2' panicked at tests/test_timeout.rs:104:10:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Device or resource busy" }

---- test_timeout_zero::case_3 stdout ----
thread 'test_timeout_zero::case_3' panicked at tests/test_timeout.rs:104:10:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Device or resource busy" }


failures:
    test_read_returns_available_data_before_timeout::case_1
    test_read_returns_available_data_before_timeout::case_2
    test_timeout_greater_zero::case_1
    test_timeout_greater_zero::case_2
    test_timeout_greater_zero::case_3
    test_timeout_max
    test_timeout_zero::case_1
    test_timeout_zero::case_2
    test_timeout_zero::case_3

test result: FAILED. 0 passed; 9 failed; 0 ignored; 0 measured; 0 filtered out; finished in 156.79s
[...]

My default test setup uses SiLabs CP2102N dongles and the changes makes some tests with a pair of them failing as well:

# Two CP2102N dongles
$ export SERIALPORT_TEST_PORT_1=[...]
$ export SERIALPORT_TEST_PORT_2=[...]
$ cargo test --no-fail-fast
[...]
     Running tests/test_baudrate.rs (target/debug/deps/test_baudrate-2cc756afd9f0c4cf)

running 27 tests
test builder::test_non_standard_baud_rate_fails_where_not_supported::case_1 ... ignored
test builder::test_non_standard_baud_rate_fails_where_not_supported::case_2 ... ignored
test builder::test_non_standard_baud_rate_fails_where_not_supported::case_3 ... ignored
test builder::test_non_standard_baud_rate_succeeds_where_supported::case_1 ... FAILED
test builder::test_non_standard_baud_rate_succeeds_where_supported::case_2 ... FAILED
test builder::test_non_standard_baud_rate_succeeds_where_supported::case_3 ... FAILED
test builder::test_standard_baud_rate::case_1 ... ok
test builder::test_standard_baud_rate::case_2 ... ok
test builder::test_standard_baud_rate::case_3 ... ok
test new::test_non_standard_baud_rate_fails_where_not_supported::case_1 ... ignored
test new::test_non_standard_baud_rate_fails_where_not_supported::case_2 ... ignored
test new::test_non_standard_baud_rate_fails_where_not_supported::case_3 ... ignored
test new::test_non_standard_baud_rate_succeeds_where_supported::case_1 ... FAILED
test new::test_non_standard_baud_rate_succeeds_where_supported::case_2 ... FAILED
test new::test_non_standard_baud_rate_succeeds_where_supported::case_3 ... FAILED
test new::test_standard_baud_rate::case_1 ... ok
test new::test_standard_baud_rate::case_2 ... ok
test new::test_standard_baud_rate::case_3 ... ok
test set_baud::test_non_standard_baud_rate_fails_where_not_supported::case_1 ... ignored
test set_baud::test_non_standard_baud_rate_fails_where_not_supported::case_2 ... ignored
test set_baud::test_non_standard_baud_rate_fails_where_not_supported::case_3 ... ignored
test set_baud::test_non_standard_baud_rate_succeeds_where_supported::case_1 ... ok
test set_baud::test_non_standard_baud_rate_succeeds_where_supported::case_2 ... ok
test set_baud::test_non_standard_baud_rate_succeeds_where_supported::case_3 ... ok
test set_baud::test_standard_baud_rate::case_1 ... ok
test set_baud::test_standard_baud_rate::case_2 ... ok
test set_baud::test_standard_baud_rate::case_3 ... ok

failures:

---- builder::test_non_standard_baud_rate_succeeds_where_supported::case_1 stdout ----
thread 'builder::test_non_standard_baud_rate_succeeds_where_supported::case_1' panicked at tests/test_baudrate.rs:86:14:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- builder::test_non_standard_baud_rate_succeeds_where_supported::case_2 stdout ----
thread 'builder::test_non_standard_baud_rate_succeeds_where_supported::case_2' panicked at tests/test_baudrate.rs:86:14:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }

---- builder::test_non_standard_baud_rate_succeeds_where_supported::case_3 stdout ----
thread 'builder::test_non_standard_baud_rate_succeeds_where_supported::case_3' panicked at tests/test_baudrate.rs:86:14:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }

---- new::test_non_standard_baud_rate_succeeds_where_supported::case_1 stdout ----
thread 'new::test_non_standard_baud_rate_succeeds_where_supported::case_1' panicked at tests/test_baudrate.rs:129:67:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }

---- new::test_non_standard_baud_rate_succeeds_where_supported::case_2 stdout ----
thread 'new::test_non_standard_baud_rate_succeeds_where_supported::case_2' panicked at tests/test_baudrate.rs:129:67:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }

---- new::test_non_standard_baud_rate_succeeds_where_supported::case_3 stdout ----
thread 'new::test_non_standard_baud_rate_succeeds_where_supported::case_3' panicked at tests/test_baudrate.rs:129:67:
called `Result::unwrap()` on an `Err` value: Error { kind: Unknown, description: "Invalid argument" }


failures:
    builder::test_non_standard_baud_rate_succeeds_where_supported::case_1
    builder::test_non_standard_baud_rate_succeeds_where_supported::case_2
    builder::test_non_standard_baud_rate_succeeds_where_supported::case_3
    new::test_non_standard_baud_rate_succeeds_where_supported::case_1
    new::test_non_standard_baud_rate_succeeds_where_supported::case_2
    new::test_non_standard_baud_rate_succeeds_where_supported::case_3

test result: FAILED. 12 passed; 6 failed; 9 ignored; 0 measured; 0 filtered out; finished in 37.71s
[...]

I will have a more in-depth look into this the next days. But at a first glance this looks like - besides the timing issue with the PL2303 - the changes are breaking baud rate setting via serialport::new and SerialPortBuilder. I bet we'll get this sorted out soon.

Could you please give the tests a spin in your setup @skmagiik or @pmnxis?

@sirhcel
Copy link
Contributor

sirhcel commented Feb 9, 2025

Looking deeper into my results from #194 (comment) with an oscilloscope, I was surprised that I did see data output from the PL2303 cable (with a blue connector housing) only in rare cases. For example, running the example transmit.rs gave a single byte output at the very beginning most of the time but no periodic output.

I did testing with macOS 10.15.3 on a M1 machine using the driver shipped with the OS. I learned that there is also a driver from Prolific distributed via the Mac AppStore and with this one, things look better: Some test cases are still failing (with timeouts) but baud rate setting and transmitting at the set speed (with sirhcel@51df58f) seems possible.

Which version of macOS, which CPU architecture and witch device driver are you using @skmagiik and @pmnxis?

@pmnxis
Copy link

pmnxis commented Feb 9, 2025

@sirhcel Hello Thanks for looking on this issue , it would be very helpful.
First my macOS environment is 14.3(15.2) with M4 series. (and chip is PL2303HXA)

I am working on egui based serial-terminal on macOS/Linux/Windows.
PL2303 was worked with original serialport-rs with Linux/Windows, but macOS.

Some interesting thing is that the some of PL2303 is a counterfeited chip from China, and it's not clear how it will behave on a macOS depending on whether it's a counterfeited or legit. I'll try to get a good PL2303 and a cloned PL2303 and compare the differences.

And may need check if all of prolific's products have different termios access. The code I forcibly modified with unsafe is a hotfix method used by prolific in macOS environments, but I'm not sure if it's a good method because I only tested it on PL2303HX.
https://github.com/pmnxis/egui_term/blob/serial-tty-rename-proposal/src/serial_tty/mod.rs#L188-L213

@pmnxis
Copy link

pmnxis commented Feb 10, 2025

I confirmed following devices were working with modified method in macOS

image
mfn : Prolific Technology Inc.
UsbPortInfo { vid: 1659, pid: 8963, serial_number: None, manufacturer: Some("Prolific Technology Inc."), product: Some("USB-Serial Controller") }
image
mfn : STMicroelectronics
UsbPortInfo { vid: 1155, pid: 14159, serial_number: Some("0029002E3156501320323443"), manufacturer: Some("STMicroelectronics"), product: Some("STLINK-V3") }
Device Original iossiospeed cfsetispeed / cfsetospeed
Counterfeited PL2303HXA Not working Working
Prolific PL2303 Not working Working
ST Micro ST Link V3 UART Bridge Working Working
FTDI ---- Not tested Not tested yet
CP ---- Not tested Not tested yet

@sirhcel
Copy link
Contributor

sirhcel commented Feb 10, 2025

I am working on egui based serial-terminal on macOS/Linux/Windows. PL2303 was worked with original serialport-rs with Linux/Windows, but macOS.

I have not booted up Windows yet, but running my test from above on Linux worked just fine.

Some interesting thing is that the some of PL2303 is a counterfeited chip from China, and it's not clear how it will behave on a macOS depending on whether it's a counterfeited or legit. I'll try to get a good PL2303 and a cloned PL2303 and compare the differences.

I read about it. And was wondering what I have bought because of the strange behavior with the driver shipped with Sequoia. Sourcing PL2303 devices feels a bit challenging as my usual "purveyors of the court" do not list them. So i ended up buying some cables at Amazon. Let alone soucing individual ICs.

Do you have a trusty source for PL2303 ICs or devices? How do you tell genuine and fake devices apart?

Looking at the screenshots in #194 (comment): Where do you get this information about the assocated device driver from?

@pmnxis
Copy link

pmnxis commented Feb 11, 2025

Do you have a trusty source for PL2303 ICs or devices? How do you tell genuine and fake devices apart?
I tired to connect PL2303 device to Windows, When it's counterfeited one,devmgmt.msc says pl2303hxa phased out since 2012 not working

image
I have never purchased PL2303 directly from a dealer. When I purchased it directly, I think I purchased CPxxxx.
I live in Korea, so the marketplace is very different, so I can't give you a definitive answer, but I remember that the waveshare PL2303 module I purchased 4 years ago wasn't a counterfeit.

Looking at the screenshots in #194 (comment): Where do you get this information about the assocated device driver from?

It's decisivetactics's commercial software, Serial 2.
Since it is open source, I thought it would be better to show it through macOS's built-in System Report, but question about asking which device driver used.
So I checked it with that commercial software.
image

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.

Data misread from serial adapter (serialport only)
3 participants