de-vri-es / serial2-rs

Cross platform serial ports for Rust
Other
48 stars 11 forks source link

add rs485 support #29

Closed omelia-iliffe closed 5 months ago

omelia-iliffe commented 7 months ago

Initial attempt with the rs485 crate and adding the struct to the settings. I have tested with an rs485 board and it works. It will currently fail with a non rs485 device so need to add some checks to the get_from_file fn

de-vri-es commented 7 months ago

Thanks for the PR!

I think I like the approach of making it part of the Settings. Even if it doesn't map to the termios struct, for a user I think this is an intuitive way to enable RS485 mode.

I prefer to avoid the dependency on the rs485 crate and just use libc directly.

Ideally, we would also figure out how to do this on Windows. If not, we should probably put this under the unix feature until someone can contribute a Windows implementation. But I can take care of this part if you prefer.

de-vri-es commented 7 months ago

I've been reading a bit more here: https://www.kernel.org/doc/html/v5.16/driver-api/serial/serial-rs485.html

I think the only thing we need to implement now is the SER_RS485_ENABLED flag. The rest is basically flow control for the RTS/DTR flags, so maybe that should be a new FlowControl option. But I'm pretty sure you don't need that for Dynamixels, because those pins aren't even connected :p

/edit: Actually, this one would be very nice to expose too: SER_RS485_TERMINATE_BUS. And maybe SER_RS485_MODE_RS422.

Maybe SER_RS485_ENABLED and SER_RS485_MODE_RS422 should be combined into a enum Mode { Rs232, Rs422, Rs485 }. Although the Rs232 variant is misleading, because if the serial device only supports one mode, then that mode will be used if you select Rs232...

omelia-iliffe commented 6 months ago

Although the Rs232 variant is misleading, because if the serial device only supports one mode, then that mode will be used if you select Rs232...

Its confusing as the PCIe card I am using only supports rs485 but without setting the flag to enable_rs485 it doesn't work. The device is an umbratek mpcie rs485 card with the chip a xr17v358 chip

I've embedded the rs485 crate, as its pretty minimal, I am would end up rewriting it all anyway. Modified it to work with libc crate and the latest bitflags crate.

de-vri-es commented 6 months ago

Its confusing as the PCIe card I am using only supports rs485 but without setting the flag to enable_rs485 it doesn't work. The device is an umbratek mpcie rs485 card with the chip a xr17v358 chip

yaaay :p

I've embedded the rs485 crate, as its pretty minimal, I am would end up rewriting it all anyway. Modified it to work with libc crate and the latest bitflags crate.

Sorry for the delay in review. I need to read up a bit to ensure we model this correctly. Sadly so far I can't find anything on how this is done on other platforms :(

de-vri-es commented 6 months ago

I've been working on an API that I think make sense. Sorry for the radio silence.

This ioctl is another can of worms in the serial communication landscape, so I want to take some time to model it correctly.

What I'm leaning towards now is an API to specifically configure RS-485 and RS-422, where things like the RTS signal state and bus termination is only available in RS-485 mode.

I'm also limiting the exposed settings, since even the Linux kernel actually "sanitizes" the options silently. For example, if you set RTS_ON_SEND and RTS_AFTER_SEND to the same value, the kernel simply sets both of them to pre-determined value: https://github.com/torvalds/linux/blob/f2f80ac809875855ac843f9e5e7480604b5cbff5/drivers/tty/serial/serial_core.c#L1382-L1399

Also, the MODE_RS422 flag is currently not used by any mainline driver: https://github.com/search?q=repo%3Atorvalds%2Flinux%20RS485_MODE_RS422&type=code

But one of them interprets RX_DURING_TX as RS-422 mode: https://github.com/torvalds/linux/blob/f2f80ac809875855ac843f9e5e7480604b5cbff5/drivers/tty/serial/8250/8250_exar.c#L506-L516

But I intend to solve most of this with warnings in the documentation rather than hacks to detect device quirks.

omelia-iliffe commented 5 months ago

No worries about the radio silence, and thanks for continuing to work on it. Its a complicated problem, but your approach sounds good. Looking forward to seeing it. :)

de-vri-es commented 5 months ago

I've pushed some commits to adjust the API. For usage, you can check the rs485 example.

I will still go over the changes again later, when I've had some time to let it sink :)

DanielJoyce commented 5 months ago

This is nice, but also a lot of people simply emulate this stuff throygh the already available R232 features. Its nice to have, but maybe a comment about bitbanging it yourself over regular serial is also possible if stuff doesn't work.

omelia-iliffe commented 5 months ago

I confirmed this works for my setup today and the ergonomics seem nice to me. I noticed a couple of minor mistakes ill fix now.

@DanielJoyce I'm not sure how you could emulate the switching of ioctls with bitbanging. Perhaps you could write the comment as you suggested with an example?

de-vri-es commented 5 months ago

I confirmed this works for my setup today and the ergonomics seem nice to me. I noticed a couple of minor mistakes ill fix now.

:+1:

I'll wait for your fixes before merging.

@DanielJoyce I'm not sure how you could emulate the switching of ioctls with bitbanging. Perhaps you could write the comment as you suggested with an example?

I think they mean that you can switch the RTS/DTR signals manually in between calls to read() and write(). But I'm not sure if that is enough in all cases. RS-485 and RS-422 require a different transceiver (with different electrical properties) from RS-232. The kernel documentation is very vague in exactly what SER_RS485_ENABLED and SER_RS485_MODE_RS422 really do. But maybe they change the active transceiver to really switch between RS-232 and RS-485/RS-422 for some devices.

(Technically, RS-422 has different electrical properties from RS-485 too, but a RS-485 transceiver should be backwards compatible with RS-422.)

DanielJoyce commented 5 months ago

RS485 is a two wire protocol as specd. Extra wires are not supported by everyone.

What I mean by bit banging is if your rs485 port is exposing a dtr pin and Linux doing the twiddling for you isn't working, as long as Linux exposes that DTR you can twiddle it yourself

DanielJoyce commented 5 months ago

Like how currently the crate exposes the pins for rs232 and we can set them high / low manually.

omelia-iliffe commented 5 months ago

whoops sorry I thought I had replied. Ready to merge @de-vri-es :)

de-vri-es commented 5 months ago

No problem! Released as v0.2.22 \o/