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.
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
Why Can Template Instances Not Be Deduced in 'Std::Reference_Wrapper'S
Non-Const Reference May Only Be Bound to an Lvalue
Enumerate Com Object (Idispatch) Methods Using Atl
Add Library Search Path to Clang
Why Ld_Preload Doesn't Work for One of Loaded Shared Libraries
Locating iOStream in Clang++: Fatal Error: 'iOStream' File Not Found
Linux Executable Can't Find Shared Library in Same Folder
Why How to Implicitly Convert an Int Literal to an Int * in C But Not in C++
Has a Std::Byte Pointer the Same Aliasing Implications as Char*
Good C++ Array Class for Dealing with Large Arrays of Data in a Fast and Memory Efficient Way
What Does the C++ New Operator Do Other Than Allocation and a Ctor Call
Heapcreate, Heapalloc in Linux, Private Allocator for Linux
Adding Header and .Cpp Files in a Project Built with Cmake
Partial Template Specialization Based on "Signed-Ness" of Integer Type
Boost Spirit X3: Parse into Structs
Warning: Narrowing Conversion C++11
What Does a Comma Separated List of Values, Enclosed in Parenthesis Mean in C? a = (1, 2, 3);