How to probe if a serial port has a valid connection?
To cut to the point.
I wrote a serial port testing program, which tests ports using a hardware loopback.
The problem I bumped into was that if the device "existed" in the /dev dir, but nothing was connected on it, I could open and write to the port, but trying to read or close it, would hang up the process. I resolved the read part by by doing a clone on the read function, and then terminating the child process after some delay. But that still leaves the close function, which still hangs up the program.
Now I would like to know if there is a way, either by using a termios flag, or something similar, that can be coded into a C program, that can probe to see if the port has a connection.
If needed I can provide the code (it's GPL ofc ^^).
Well, this is something that I happen to know a little bit about.
Opening and closing a serial port with no device connected should not hang. The open()/close() functions do not communicate with the connected device and are always unaware of the presence of something on the other end (the "other end" being the same machine in the case of a loopback adapter).
To avoid read() hangs when no data is being received, you can do something like the following:
1) After opening the serial port device, set it to non-blocking mode. This means that read() will return immediately (with the error EAGAIN) if no bytes were waiting in the buffer to be read, and write() will return immediately (with EAGAIN) if the device was busy and the bytes could not be sent:
Now, I know, you could compress the above code into just a few lines, but I'm trying to keep it readable. You'd also want to add any termios configuration code to that function as well, of course (like setting the baud rate, flow control, linefeed translations, etc). Also don't forget to set CLOCAL in your tcattr c_cflags (see termios man page) if you aren't using a modem; that will cause the drivers to ignore all the modem control lines (although that one might be set by default, can't remember).
Setting nonblocking mode won't solve the problem completely by itself. Although read() won't hang, it is very possible that it will return before the number of bytes you asked for was read. Using select() combined with repeated read() calls will let you control the timeout time and also make sure you receive all the bytes you asked for, while using minimal system resources.
2) Now when you want to read() from the device, you may use select() to wait for data with a timeout, and return if no data was waiting to be read after some amount of time (thus preventing the infinite wait for data to come in). Yes, it adds some extra code, but you do what you have to do (and it's a lot less hacky and way more efficient than forking off child processes to read data):
The write() logic is similar to the above. However, write() is probably not going to timeout, so you don't necessarily need to use select() to wait for the descriptor to be available for writing; you can just get away with writing bytes and incrementing through the source buffer as above.
With regards to "can I check to see if there's a connection available"... not directly, I don't think. If your device sets one of the other lines high when it is connected (one of those modem lines, like CTS and crap, I don't know much about those) then you should be able to detect if the line is high or not; but chances are your device isn't like that.
However, assuming that your connected device gives some responses to the data you send to it, checking for it's presence is as simple as sending some data to it and seeing if you receive what you expect back from it without timing out. For example, with your loop back connector, all you have to do is send a few bytes. If you don't receive them back, then the connector was not attached. For something like say, a modem, or some other device, you could send some harmless command (like a status command or something) and make sure you get a valid response in a reasonable amount of time. More of a "You there? Yeah I'm here" approach than a "I know you're out there" approach.
Hope that helps,
Thanks, I did use NONBLOCKING, but must have misunderstood the part about select in the howto I have read.
This came in really handy :)
Keep up the good work.
|All times are GMT -5. The time now is 03:30 PM.|