How to Efficiently Wait for Cts or Dsr of Rs232 in Linux

How to efficiently wait for CTS or DSR of RS232 in Linux?

There is the ioctl TIOCMIWAIT which blocks until a given set of signals change.

Sadly this ioctl is not documented in the tty_ioctl(4) page nor in ioctl_list(4).

I have learned about this ioctl in this question:

Python monitor serial port (RS-232) handshake signals

Python monitor serial port (RS-232) handshake signals

On Linux is possible to monitor che state change of a signal pin of an RS-232 port using interrupt based notification throught the blocking syscall TIOCMIWAIT:

from serial import Serial
from fcntl import ioctl
from termios import (
TIOCMIWAIT,
TIOCM_RNG,
TIOCM_DSR,
TIOCM_CD,
TIOCM_CTS
)

ser = Serial('/dev/ttyUSB0')

wait_signals = (TIOCM_RNG |
TIOCM_DSR |
TIOCM_CD |
TIOCM_CTS)

if __name__ == '__main__':
while True:
ioctl(ser.fd, TIOCMIWAIT, wait_signals)
print 'RI=%-5s - DSR=%-5s - CD=%-5s - CTS=%-5s' % (
ser.getRI(),
ser.getDSR(),
ser.getCD(),
ser.getCTS(),
)

How do I force a serial port write method to wait for the line to clear before sending its data?

Flow control is the correct answer here, and it may not be present/implemented/applicable to your bluetooth connection.

Check out the Zebra specification and see if they implement, or if you can turn on, software flow control (xon, xoff) which will allow you to see when the various buffers are getting full.

Further, the bluetooth radio is unlikely to be capable of transmitting faster than 250k at the maximum. You might consider artificially limiting it to 9,600bps - this will allow the radio a lot of breathing room for retransmits, error correction, detection, and its own flow control.

If all else fails, the hack you're using right now isn't bad, but I'd call Zebra tech support and find out what they recommend before giving up.

-Adam

What is the difference between DTR/DSR and RTS/CTS flow control?

  • DTR - Data Terminal Ready
  • DSR - Data Set Ready
  • RTS - Request To Send
  • CTS - Clear To Send

There are multiple ways of doing things because there were never any protocols built into the standards. You use whatever ad-hoc "standard" your equipment implements.

Just based on the names, RTS/CTS would seem to be a natural fit. However, it's backwards from the needs that developed over time. These signals were created at a time when a terminal would batch-send a screen full of data, but the receiver might not be ready, thus the need for flow control. Later the problem would be reversed, as the terminal couldn't keep up with data coming from the host, but the RTS/CTS signals go the wrong direction - the interface isn't orthogonal, and there's no corresponding signals going the other way. Equipment makers adapted as best they could, including using the DTR and DSR signals.

EDIT

To add a bit more detail, its a two level hierarchy so "officially" both must happen for communication to take place. The behavior is defined in the original CCITT (now ITU-T) standard V.28.

Sample Image

The DCE is a modem connecting between the terminal and telephone network. In the telephone network was another piece of equipment which split off to the data network, eg. X.25.

The modem has three states: Powered off, Ready (Data Set Ready is true), and connected (Data Carrier Detect)

The terminal can't do anything until the modem is connected.

When the terminal wants to send data, it raises RTS and the modem grants the request with CTS. The modem lowers CTS when its internal buffer is full.

So nostalgic!

Detecting if a character device has disconnected in Linux in with termios api (c++)

First of all it worth mentioning, that the behavior serial-usb is following:

On usb device unplugged disconnect is called

@disconnect: Called when the interface is no longer accessible, usually
because its device has been (or is being) disconnected or the
driver module is being unloaded.

in our case it is usb_serial_disconnect(struct usb_interface *interface)

which calles usb_serial_console_disconnect(serial), which calles tty_hangup ... and so on.

You can follow chain started from here:
http://lxr.free-electrons.com/source/drivers/usb/serial/usb-serial.c#L1091

In short this results in following classic manner:

pselect signals that file descriptor is ready and ioctl(fd, FIONREAD, &len) returns zero len.

That's it you unplugged the device.

Summurizing (derived from your code) :

while(1)
{
FD_ZERO(&rfds);
FD_SET(tty_fd, &rfds);

// have tried checking fcntl(tty_fd, F_GETFL); too

// Blocking call to wait until we have data
int ready = select(tty_fd + 1, &rfds, NULL, NULL, NULL);

if(ready && FD_ISSET(tty_fd, &rfds)) {
size_t len = 0;
ioctl(tty_fd, FIONREAD, &len);
errsv = errno;

if(len == 0)
{
printf("prog_name: zero read from the device: %s.", strerror(errsv));
/* close fd and cleanup or reconnect etc...*/
exit(EXIT_FAILURE);
}

// While we have data, collect it
while (read(tty_fd, &c, 1)>0 && bytesRead++<200)
{
serialBuffer.push_back(c);
}

bytesRead = 0;

// Try to parse it
BufferParse();
}
}

It's a pity that you did not say what kind of device you are using.

In case if your device is capable of RTS/CTS flow control it is also possbile to detect line break.



Related Topics



Leave a reply



Submit