1

I have an app that expects to do I/O over a full-duplex serial line. That is:

char buf[4];
write(fd, "ping", 4);
read(fd, buf, 4);

... expects to end up with whatever four bytes the remote device transmitted in response to the "ping" string.

But I'm running on a half-duplex RS485 line, so every byte that gets transmitted on the serial line is also received on the on the serial line (because they are the same line). So the code snippet above always reads "ping" into the buffer before the remote device transmits anything.

Obviously the host code isn't expecting this.

The best solution I've come up with is to always to a read following a write and verify that the received characters match those that were sent, and then to ignore them.

But is there a better way? Is there a reliable Unix idiom for inhibiting the reception of characters during the time that characters are being transmitted?

(I appreciate that there are lots of subtleties and twisty little mazes in my question. For example, does the UART have a fifo? Is the receive process running in the same thread? Etc. If it was easy, I wouldn't be asking unix.stackexchange! :)

update

I implemented a simple routine that I call after each write() to read() an equivalent # of bytes and then uses strncmp() to verify that they match. It appears to be robust, but I'm still interested to know if there's a driver level approach that might do this better, or at least differently.

  • Do you mean that either the other device or your own device echoes what is written to it? That has nothing to do with full-duplex vs. half-duplex, it's a feature of the line discipline. Check the various echo settings with stty on both sides (see man stty), and turn them off. – dirkt Oct 8 '17 at 4:53
  • No, I mean the physical wiring of RS485 is responsible: there is one pair of wires between host and client, and one or the other drives it at a time. If you're not familiar with RS485, here's an overview: bb-elec.com/Learning-Center/All-White-Papers/Serial/… – fearless_fool Oct 8 '17 at 4:57
  • I would expect the RS485 hardware to have an option that inhibits reception in two-wire mode whenever the hardware is driving the wires. Please update the question with the brand of model of RS485 adapter you use, with the chipset in that if you know it, and with the driver Linux uses for it. – dirkt Oct 8 '17 at 5:11
  • I would expect the same, but the RS485 to USB adaptor is built into my client's hardware and -- as sensible as it would be -- it lack the "inhibit rx during tx feature". Not something I have control over. – fearless_fool Oct 8 '17 at 5:38
  • There should be an ioctl to transition the adapter between tx and rx; in fact, it's hard to see it operating half-duplex otherwise. Your code need to do that at least; whether there's an echo problem or not. – Ralph Rönnquist Oct 8 '17 at 6:42
2

Pragmatically, if what you have seems to work, and you are not expecting any change in the setup, or it is a one-off hack, then stay with your solution.

However, Linux has an API for rs485 for appropriate hardware, that you can try. Some hardware has a built-in half-duplex mode that will work if you put the serial port in the appropriate state. The ioctls are, for example, to enable RS485 mode:

#include <linux/serial.h>
struct serial_rs485 rs485conf = {0};
rs485conf.flags |= SER_RS485_ENABLED;
if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) ...

or set logical level for RTS pin equal to 1 when sending:

rs485conf.flags |= SER_RS485_RTS_ON_SEND;
  • This answers my original question -- thanks. As an aside, the read() and strncmp() approach is doing the right thing, and is mostly compatible with the Windows version of the code, so I'll probably stick with that. – fearless_fool Oct 10 '17 at 14:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.