C Call like select/poll for com port

Colleagues, please tell me if there is a call like select / poll, but for working with a com port?
I want to see that data has been received or data has been transmitted. And see that the control signals of the port have changed.

As far as I understand, select and poll calls work with a network socket, but is it possible to get the status of a serial port in a similar way?

Grateful for the answer,
Ogogon.
 
Normally, when you open a tty, the system call will stall until a carrier is present, at which time the open will return.

You can set the O_NDELAY flag (now called O_NONBLOCK) to prevent the open from stalling on carrier detect.

See tty(4) for the ioctls you can do once you have the file descriptor.
 
As far as I understand, select and poll calls work with a network socket,
No, they work on any file descriptor. The restriction on sockets is only present in the Windows port, they implemented BSD sockets, so they needed these functions too, but restricted them to sockets.

But, these functions only tell you which fd is ready for reading or writing (won't block on these operations), so I don't think this is enough for your purpose.

Could you explain what you try to achieve? These functions are typically used for I/O multiplexing, so do you have other I/O to do "at the same time"? Or do you just want to do some other work while waiting for something on the port, then maybe a thread would make more sense?
 
I've done much what zirias@ says. select/poll and variants work on all fds, make sure you understand what the bit masks actually mean and when they get cleared/not cleared. Setting the fd to non blocking, using select/poll and a thread then all you need to do is worry about the trivial aspects like synchronizing read/write of data (I'm joking about the trivial, it's not)
 
Could you explain what you try to achieve?
Of course. I want to write a terminal program that not only transmits and receives bytes, but also constantly monitors the signals of the RS-232 interface, reacts to their changes in a given way and displays their status.
I already understood that poll() can work with the handle of an open com port. Is it possible, at the same time, to control the change in the state of the control signals of the port (CTS,DSR,DCD)?
 
I already understood that poll() can work with the handle of an open com port. Is it possible, at the same time, to control the change in the state of the control signals of the port (CTS,DSR,DCD)?
These are not signals, they are physical wires. These wires are then connected to register addresses; I have a reference, but that is translated into German, so mostly unuseable (what is 'DCD' in German?).

So this is basically a register read on the i/o-page - but such register reads are normally done by the device-driver inside the kernel, and them provided to the application as ioctl() (TIOCMGET/TIOCMSET, tty(4)).

In order to "monitor" such a state, something needs to repeatedly read that register. I don't think the uart() driver does that, I think it just reads the register when an ioctl() is requested. And from what I understand, the uart might create interrupts when a complete byte has been received; but I don't think it can create interrupts when just a wire toggles. (But I don't know for certain, this might be investigated.)

So probably the application will have to do repeated ioctl(), one way or the other.
 
  • Like
Reactions: _al
from what I understand, the uart might create interrupts when a complete byte has been received; but I don't think it can create interrupts when just a wire toggles. (But I don't know for certain, this might be investigated.)
The classic state transition is Data Carrier Detect (DCD or CD). The usual way of detecting a carrier state change is for the driver to check the hardware for a state change when you get a receiver interrupt (character present) on a tty whose state is "open" or "stalled in open, waiting for carrier". So no, DCD does not usually generate an interrupt, but it's noticed as soon as it needs to be.

The other RS232 (and similar) signals are usually manipulated by the driver as and when needed. e.g. the driver's open routine will typically turn on DTR and RTS, and the close routine will drop them.
 
I have a reference, but that is translated into German, so mostly unuseable (what is 'DCD' in German?).
"Datenträgersignal erkannt". But, in fact, in German, English abbreviations from the EIA-232 specification are used.

As a German who has lived all his life in another country and a completely different ethnic culture, I have a very great abstract respect for the Great German language. Therefore, if it's not difficult for you, send this reference, I will try to figure it out.
 
I want to write a terminal program that not only transmits and receives bytes, but also constantly monitors the signals of the RS-232 interface, reacts to their changes in a given way and displays their status.
As for event-driven serial port programming, I only found this (for win32) - https://www.tetraedre.com/advanced/serial2.php (maybe this will help somehow, give you an idea)

I myself worked with com ports only in windows (very long time ago) - with smard card simulators, connected to PC via COM-port (using Win32 API - CreateFile, Get/SetCommState, Get/SetCommTimeouts, GetOverlappedResult, ...)
 
Well, you won't be able to learn about changes of these signals with poll/select, they're really limited to reading/writing to/from the file descriptor. The naive approach would be to have a thread issuing the ioctl()s for reading these signals at a constant rate, and if something changes, write some value to a pipe. The other end of the pipe could be monitored with poll/select. But of course, I/O triggered from userspace is expensive.

So, what you really want is a way to tell the kernel to wait for that and only unblock you once something changed. I have no idea about the serial port APIs available in FreeBSD, so I don't know whether something like this exists. You could of course write a kernel module 🙈
 
  • Like
Reactions: _al
"Datenträgersignal erkannt". But, in fact, in German, English abbreviations from the EIA-232 specification are used.
Eventually, my toenalls already rolled up when I got to "Line-Steuerregister" and "interrupt-Identifizierungs-Register". I really don't want to translate this back into English to figure where it goes.

As a German who has lived all his life in another country and a completely different ethnic culture, I have a very great abstract respect for the Great German language.
Sounds interesting...
But no, the great German language :) is not well suited for this kind of intermixed shashlik.

Therefore, if it's not difficult for you, send this reference, I will try to figure it out.
I'll see if I can make a photo. It's an old book describing all the bits&bytes of the IBM PC/XT and PC/AT.
 
So, what you really want is a way to tell the kernel to wait for that and only unblock you once something changed. I have no idea about the serial port APIs available in FreeBSD, so I don't know whether something like this exists. You could of course write a kernel module 🙈
Hm, what is with this /dev/io thing? Aka io(4). Could that be used?
Originally this was supposed to directly read+write i/o registers and talk to devices from userspace. But something then had changed there, and I did not use it anymore because machines got more complex anyway.
 
So, what you really want is a way to tell the kernel to wait for that and only unblock you once something changed. I have no idea about the serial port APIs available in FreeBSD, so I don't know whether something like this exists. You could of course write a kernel module 🙈
I have now re-read the description of programming the UART 8250 and 16550 chips. (The last time I wrote something for them was in the days of Xenix 386, Unix Interactive and the FOSSIL driver.)

These chips have a Modem Status Register (BaseAddress+6, Read Only)
bit 0: Change on the CTS line
bit 1: Change on DSR line
bit 2: Change on line RI
bit 3: Change on DCD line
bit 4: Active signal on the CTS line
bit 5: Active signal on DSR line
bit 6: Active signal on RI line
bit 7: Active signal on DCD line

At the same time, in the Interrupt Enable Register (BaseAddress+1, Write Only)
bit 0: Generate an interrupt when ready to receive data
bit 1: Generate an interrupt when the transmit register is empty
bit 2: Generation of an interrupt in case of a change in the line status register (BA+5)
bit 3: Interrupt generation in case of modem status register change (BA+6)
bits 4-7: Not used in 8250 and 16550 UART
there is bit 3, which enables an interrupt in case of a change in the state of the signals CTS, DSR, RI and DCD.

Can't I enable such an interrupt and get information about it by the mask of the select/poll multiwait functions?
 
(The last time I wrote something for them was in the days of Xenix 386, Unix Interactive and the FOSSIL driver.)
That sounds familiar...
there is bit 3, which enables an interrupt in case of a change in the state of the signals CTS, DSR, RI and DCD.
See, it is there, I just didn't get it from that wording...
Can't I enable such an interrupt and get information about it by the mask of the select/poll multiwait functions?
I think you can...
Maybe this is interesting: sys/dev/uart/uart_core.c
Code:
/*
 * Line or modem status change (OOB signalling).
 * We pass the signals to the software interrupt handler for further
 * processing. Note that we merge the delta bits, but set the state
 * bits. This is to avoid losing state transitions due to having more
 * than 1 hardware interrupt between software interrupts.
 */
[...]
        /*
         * Keep track of signal changes, even when the device is not
         * opened. This allows us to inform upper layers about a
         * possible loss of DCD and thus the existence of a (possibly)
         * different connection when we have DCD back, during the time
         * that the device was closed.
         */

Apparently there is something in place already... which may be more or less useable... happy reading! :)
 
Can't I enable such an interrupt and get information about it by the mask of the select/poll multiwait functions?
I wouldn't count on that. The interrupts are handled by the kernel/driver. Signalling "ready to read/write" to userspace on some signal line change doesn't seem like an obvious choice :-/

But as mentioned by PMc reading the driver's code might clarify things 🙈
 
I wouldn't count on that. The interrupts are handled by the kernel/driver. Signalling "ready to read/write" to userspace on some signal line change doesn't seem like an obvious choice :-/
No, I would expect it to be necessary to adapt/change that device driver someway. But the required pieces, e.g. these interrupts, are already in there, and so it should not get too difficult. Then define a new sysctl, and make the code variant optional to activate via that sysctl - so you can always see if some kernel is modified and if the change is currently engaged.
 
did you look here?
Thank you. I looked at this tutorial. I even remembered the times when I worked in a company that produces its own 4- and 8-channel com-port controllers on the ISA bus.
But either I didn’t look carefully, or there is nothing there about how to enable the modem signal state change interrupt and start seeing it through the multi-wait mask.
 
If I understood correctly, then cunning Linuxoids figured out how to solve this problem.
Linux has ioctl TIOCMIWAIT, which allows the process to sleep until the state of these four modem lines changes.

TIOCMIWAIT
Argument: int arg

Wait for any of the 4 modem bits (DCD, RI, DSR, CTS) to
change. The bits of interest are specified as a bit mask
in arg, by ORing together any of the bit values,
TIOCM_RNG, TIOCM_DSR, TIOCM_CD, and TIOCM_CTS. The caller
should use TIOCGICOUNT to see which bit has changed.

In other words, if I understand correctly, I can start a separate thread, which will always stand on this ioctl, and when changes occur, notify whoever needs it. And so in the cycle.

But I didn't find such ioctl in BSD...
 
I'm not familiar with Linux/FreeBSD serial port programming (user and kernel mode ).
I've only worked with serial ports on Windows (from user mode).
In kernel mode (when we developed our Smart Card OS on NXP P5 SmartMX (descendant of 80C51) microcontroller) , I have worked with ISO 7816-3 UART (book "C and the 8051", 4th ed. by Thomas Schultz helped me a lot).

As for 'ioctl TIOCMIWAIT' , I think you're right - there's no such thing in FreeBSD, a quick search confirms this:
 
Back
Top