在输入中使用固定数据进行非阻塞读取 [英] Non blocking read with fixed data in input

查看:279
本文介绍了在输入中使用固定数据进行非阻塞读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用串口与其他设备进行通信txdev,问题是txdev异步发送数据,我不希望读取函数来阻止,好的是,txdev正在发送固定大小的数据,但我不知道如何使用这个技巧。
我所做的是以下内容:

  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 这篇文章我不支持这导致读取被阻止VTIME = 0也被阻止。



任何人都可以帮我找出解决方案,我想我必须使用中断处理程序而不是读取你同意吗?


第二个问题:由于发件人无法与接收器同步,因此有一个中断处理程序将接收的数据存储在指定的缓冲区上(我不支持规范模式的情况,但不是非法规模式),或者只有在读取函数时才能完成,如果我错了,请更正我



As通常非常感谢。

解决方案


我想使用串口与其他设备进行通信txdev,问题是txdev异步发送数据,我不会读取功能阻止,


您似乎误解了Linux应用程序如何从串行端口读取和写入。所有数据在程序和UART之间进行缓冲。您的程序不必总是随时随地阅读数据,因为它脱离了电线。操作系统(特别是UART设备驱动程序和包括线路规则的tty子系统)执行此操作,并缓存程序的数据。



RS-232根据定义是异步通信链路。字符/字节可以随时发送。消息包将到达任何时间点,因此应用程序将不得不等待包含消息包的字节。这是使用阻止读取的情况。



接收串行数据的典型问题是如何对接收到的数据执行词法扫描,以识别完整的消息数据包。短信(规范模式)只需使用ASCII行控制字符来分隔消息/行。即使是固定长度的数据包也需要验证(以确保消息实际上在正确的字节上开始)。请参阅扫描固定长度数据包的示例


我想我必须使用中断处理程序而不是阅读你同意吗?


不,UART设备驱动程序已经服务于其中断(或采用DMA)捕获从串行链路接收的每个字节。


由于发件人无法与接收器同步,因此有一个中断处理程序将接收到的数据存储在指定的缓冲区上(我不支持标准模式的情况,规范模式),或者仅在达到读取功能时才能完成此操作。


接收端不需要串行端口与字节级别的发送串行端口同步。 RS-232是一个异步通信链路:发送方可以/将在任何时间发送一个字符/字节,另一端必须准备好接收它(除非有硬件或软件流控制到位)在设备驱动程序级别(而不是应用程序)。



操作系统总是缓冲这个接收到的数据。应用程序的 read()系统调用只是从系统缓冲区到用户缓冲区的复制操作。此复制操作适用于规范和非规范模式。



同步通常是协议在消息或数据包级别解决的问题。主从是用于定义串行链路协议的常用配置。主端向从属方发送查询消息。从站必须始终准备好接收查询。从机端可以通过事务请求或数据捕获或任何或NAK消息进行响应,以指示主机没有任何内容。此请求 - 响应对话框旨在控制或调整两个单元之间的数据流(和处理负载)。



附录


我打算做的是实际上是无限循环中的阻塞读(VTIME = 0 VMIN = DATA_LENGTH)


大概您将始终在发送设备之前启动您的程序,以便第一个发送的DATA_LENGTH将与程序首次读取一致。



这可能在理想或监控的情况下大部分时间工作。

但是对于工业24/7应用程序,丢失消息的可能性帧对齐是实际的(例如发送设备在传输中间重新启动),因此没有有效手段来验证和恢复消息帧对齐的方案是不够的。



IOW串口的原始 read()可能不会在缓冲区中返回一个对齐的消息(即buf [0]可能不包含消息的第一个字节)。

一个非常小的VMIN与非零VTIME是典型的termios配置,这是基于每个消息之后串行链路空闲(短时间间隔)的前提。 >
但代码应该是鲁棒的,以处理任何/所有消息片段,因为它们被读取。因此,可能需要多个 read()来重建整个消息。


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.

解决方案

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.

这篇关于在输入中使用固定数据进行非阻塞读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆