[英]How to receive complete data from serial port in linux
I am trying to do a serial communication application. 我正在尝试进行串行通信应用程序。 I have a device which is running angstrom qt linux image.
我有一台正在运行qq linux映像的设备。 I need to write the serial code application for that device.
我需要为该设备编写串行代码应用程序。 Because the cross compiler is set for QT4.8.7, so it do not include the
QSerialPort
. 因为交叉编译器设置为QT4.8.7,所以它不包括
QSerialPort
。 So I am following this link for serial communication and I have also found many good examples on it. 因此,我正在跟踪此链接进行串行通信,并且在该链接上也找到了很多很好的例子。
Below is the code: 下面是代码:
void MainWindow::SerialOpen(QString PORT)
{
fd = open(PORT.toStdString().c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
perror("open_port: Unable to open /dev/ttyLP0\n");
exit(1);
}
saio.sa_handler = signal_handler_IO;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
fcntl(fd, F_SETFL, FNDELAY);
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, O_ASYNC );
tcgetattr(fd,&termAttr);
cfsetispeed(&termAttr,B9600);
cfsetospeed(&termAttr,B9600);
termAttr.c_cflag &= ~PARENB;
termAttr.c_cflag &= ~CSTOPB;
termAttr.c_cflag &= ~CSIZE;
termAttr.c_cflag |= CS8;
termAttr.c_cflag |= (CLOCAL | CREAD);
termAttr.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
termAttr.c_iflag &= ~(IXON | IXOFF | IXANY);
termAttr.c_oflag &= ~OPOST;
tcsetattr(fd,TCSANOW,&termAttr);
qDebug("Serial Port configured....\n");
}
and for reading I am using: 为了阅读,我使用:
void signal_handler_IO (int status)
{
char buf [100];
int n = read (fd, buf, sizeof buf);
if(n > 0)
{
buf[n] = '\0';
printf("Receive OK %s\n",buf);
}
}
I am using event based serial read. 我正在使用基于事件的串行读取。 I am wiriting it in QT creator.
我在QT创作者中撰写。 The problem I am facing is that whenever I am sending characters like
A
or B
or any other single char. 我面临的问题是,无论何时我发送诸如
A
或B
或任何其他单个字符的字符。 It receives it. 它收到它。 But when I send the complete string, it breaks automatically.
但是,当我发送完整的字符串时,它会自动中断。 Have a look at the below image:
看下图:
As you can see in the image, it receives char like p
l
h
but then I sent hello world
. 如您在图像中看到的,它像
p
l
h
一样接收char,但是随后我向hello world
发送了消息。 It breaks it and first received hello
and then world
. 它打破了它,首先收到了
hello
,然后是world
。 I again sent the hello world
it receives the he
then llo
then worl
and then d
. 我再次向
hello world
发送了消息,它收到了he
然后是llo
然后是worl
,然后是d
。 Why is this showing this behaviour. 为什么显示这种行为。 Please help.
请帮忙。 Thanks.
谢谢。
You are receiving your data in small chunks. 您正在小批量接收数据。 Try running the
read
function in a while loop to append all chunks into one message like so: 尝试在while循环中运行
read
函数,以将所有块附加到一条消息中,如下所示:
#include <cstring> // needed for strcat.
#include <errno.h> // needed for strerror and errno
void signal_handler_IO (int status)
{
char buf [100];
char msg[1024];
int n;
int length = 0;
while((n = read (fd, buf, (sizeof buf)-1)) > 0)
{
buf[n] = '\0';
// you can add a check here to see if (length+n) < 1024
strcat(msg, buf);
length += n;
}
if(n<0)
{
//error handling
//EDIT: adding error handling
fprintf(stderr, "Error while receiving message: %s\n", strerror(errno));
return;
}
printf("Receive OK: '%s'\n", msg);
}
The signal handling needs to be turned off for the time of reading data so that the signal handler doesn't get called for each new chunk of data. EDIT : Thanks to @MarkPlotnick for giving a better example on masking the signal instead of turning it off (could cause race condition). 在读取数据时需要关闭信号处理,以免对每个新的数据块都调用信号处理程序。 After we're done reading the handler needs to be restored.
阅读完之后,需要恢复处理程序。
编辑 :感谢@MarkPlotnick提供了一个更好的屏蔽信号的示例,而不是将其关闭(可能导致竞态)。 Add these two lines before calling
sigaction
to MainWindow::SerialOpen
to mask the signal so that the handler doesn't get called again while the signal is being handled: 在调用
sigaction
到MainWindow::SerialOpen
掩盖信号之前,添加以下两行,以便在处理信号时不会再次调用处理程序:
sigemptyset(&saio.sa_mask);
sigaddset(&saio.sa_mask, SIGIO);
The size of msg
is just an example, you can set it to any value that will fit the message. msg
的大小仅是示例,您可以将其设置为适合该消息的任何值。 Also, if you're using c++ then it would be better to use std::string
instead of an array for msg
. 另外,如果您使用的是c ++,那么最好使用
std::string
代替msg
的数组。
Note the (sizeof buf)-1
, if you read all characters there would be no room for the '\\0'
at the end of the array. 注意
(sizeof buf)-1
,如果您读取了所有字符,则在数组末尾没有空格来容纳'\\0'
。
ANOTHER EDIT : After our chat conversation it turned out that read
is blocking when there are no more characters to read (even though open
was called with O_NDELAY
flag for non-blocking reading). 另一个编辑 :在我们的聊天对话之后,事实证明,当没有更多字符要读取时,
read
正在阻塞(即使使用O_NDELAY
标志调用open
来进行非阻塞读取)。 To fix this issue one can first check how many bytes are available for reading: 要解决此问题,可以先检查有多少字节可读取:
while(true)
{
size_t bytes_avail;
ioctl(fd, FIONREAD, &bytes_avail);
if(bytes_avail == 0)
break;
int n = read (fd, buf, (sizeof buf)-1);
if(n<0)
{
//error handling
fprintf(stderr, "Error while receiving message: %s\n", strerror(errno));
return;
}
buf[n] = '\0';
// you can add a check here to see if (length+n) < 1024
strcat(msg, buf);
length += n;
}
QT4.8.7, so it do not include the QSerialPort
QT4.8.7,因此它不包含QSerialPort
You can build QSerialPort from sources and to use it. 您可以从源代码构建QSerialPort并使用它。 Please read Wiki: https://wiki.qt.io/Qt_Serial_Port
请阅读Wiki: https : //wiki.qt.io/Qt_Serial_Port
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.