Non blocking read with fixed data in input

2019-09-18 23:42发布

I want use serial port to communicate with another device txdev, the problem is that txdev is sending data asynchronously and i don't want the read function to block, the good thing is that txdev is sending data with fixed size but i don't know how to use this trick. what i'am doing is the following :

fd = open(DEVICE_NAME, O_RDWR | O_NOCTTY);
bzero(&termios_p, sizeof(termios_p));
termios_p.c_cflag = CS8|CSTOPB|CLOCAL|CREAD;
termios_p.c_iflag = IGNPAR;
termios_p.c_oflag  = 0;
termios_p.c_lflag = ~ICANON;
termios_p.c_cc[VMIN]=DATA_LENGTH;
termios_p.c_cc[VTIME]=10;

cfsetispeed(&termios_p, BAUDRATE);
cfsetospeed(&termios_p, BAUDRATE);  

tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&termios_p);

from this post i undrestand that this cause the read to be blocked VTIME = 0 is blocking as well.

Could anyone help me figure out the solution i think i have to use interrupt handler instead of a read do you agree ?

2nd question : Since a sender can't get synchronized with the receiver is there an interrupt handler that stores the received data on specified buffer (i undrestand that this is the case for Canonical mode but not in Non canonical mode) or this is only done when read function is reached, if i'am wrong please correct me

As usual thanks a lot.

1条回答
Deceive 欺骗
2楼-- · 2019-09-19 00:14

I want use serial port to communicate with another device txdev, the problem is that txdev is sending data asynchronously and i don't want the read function to block,

You seem to misunderstand how a Linux application program should read from and write to a serial port. All data is buffered between your program and the UART. Your program does not have to be always ready to read the data as it comes off the wire. The OS (specifically the UART device driver and the tty subsystem which includes line disciplines) does that, and buffers the data for your program.

RS-232 is by definition an asynchronous communication link. The characters/bytes can be transmitted at any time. Message packets will arrive at any point in time, so the application program will have to wait for the bytes that comprise a message packet. That's a case for using blocking reads.

The typical problem of receiving serial data is how to perform a lexical scan of received data to identify a complete message packet. Text messages (canonical mode) simply use ASCII line control characters to delimit messages/lines. Even packets of fixed length need validation (to ensure that the message actually starts on the correct byte). See this example of scanning fixed-length packets.

i think i have to use interrupt handler instead of a read do you agree ?

No, the UART device driver is already servicing its interrupts (or employing DMA) to capture every byte that is received off the serial link.

Since a sender can't get synchronized with the receiver is there an interrupt handler that stores the received data on specified buffer (i undrestand that this is the case for Canonical mode but not in Non canonical mode) or this is only done when read function is reached,

There is no need for the serial port on the receive end to "synchronize" with the sending serial port at the byte level. RS-232 is an asynchronous communication link: the sender can/will transmit a character/byte at any time, and the other end must be prepared to receive it (unless there is either hardware or software flowcontrol in place) at the device driver level (and not the application program).

The OS always buffers this received data. A read() syscall by an application program is merely a copy operation from the system buffer to the user buffer. This copy operation is for both canonical and non-canonical modes.

"Getting synchronized" is typically an issue to be resolved at the message or packet level by the protocol. Master-slave is a common configuration for defining a serial link protocol. The master side sends a query message to the slave side. The slave must always be prepared to receive a query. The slave side can respond with a transaction request or data capture or whatever, or a NAK message to indicate that it has nothing for the master. This request-response dialog is intended to control or pace the data flow (and processing load) between the two units.

Addendum

what i'am planing to do is actually a blocking read (VTIME =0 VMIN = DATA_LENGTH) in an infinite loop

Presumably you will always initiate your program before the sending device so that the first transmitted DATA_LENGTH will align with the first read by the program.

That will probably work most of the time in an ideal or monitored situation.
But for industrial 24/7 applications, the possibility of losing message frame alignment is real (e.g. sending device is restarted in middle of a transmission), and therefore a scheme that has no active means to verify and regain message frame alignment is inadequate.

IOW a raw read() of the serial port may not return an aligned message in your buffer (i.e. buf[0] may not contain the first byte of the message).
A much smaller VMIN with a nonzero VTIME is the typical termios configuration based on the premise that the serial link is idle (for a short interval) after each message.
But the code should be robust to handle any/all message fragments as they are read. So more than one read() may be needed to reconstruct the entire message.

查看更多
登录 后发表回答