我想读取串行COM端口并将数据写入LINUX中的文件。实际上我是从其他PC的超级终端发送数据的。
问题是没有while循环我只能写一行。
但是对于while(1)循环,我无法写任何文件。
否则我必须发送BIG文件,然后应用程序退出/终止并写入文件。
我的应用程序应该写入数据(它可能是2行或任何东西);之后,它必须等待下一个数据。
所以请帮帮我.....
这是我的代码
=========================================
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#define BAUDRATE B115200
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
void signal_handler_IO (int status); /* definition of signal handler */
int wait_flag=TRUE; /* TRUE while no signal received */
struct timeval timeout;
char n;
fd_set rdfs;
/*Some variables*/
int num, offset = 0, bytes_expected = 255;
main()
{
int fd,c, res,i;
char In1;
struct termios oldtio,newtio;
struct sigaction saio; /* definition of signal action */
char buf[255];
FILE *fp;
/* open the device to be non-blocking (read will return immediatly) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1)
{
perror("open_port: Unable to open /dev/ttyS0 - ");
return 1;
}
else
{
fcntl(fd, F_SETFL, 0);
n = select(fd + 1, &rdfs, NULL, NULL, &timeout);
}
fp = fopen("/root/Desktop/gccAkash/OutputLOG.txt","a+");
assert(fp != NULL);
/* install the signal handler before making the device asynchronous */
saio.sa_handler = signal_handler_IO;
sigemptyset(&saio.sa_mask);
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
/* allow the process to receive SIGIO */
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VMIN]=0; //it will wait for one byte at a time.
newtio.c_cc[VTIME]=10; // it will wait for 0.1s at a time.
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (STOP==FALSE)
{
if (wait_flag==FALSE) //if input is available
{
do {
res = read(fd,buf+offset,255);
offset += res;
} while (offset < bytes_expected);
if (offset!=0)
{
for (i=0; i<offset; i++) //for all chars in string
{
In1 = buf[i];
fputc ((int) In1, fp);
printf("charecter:%c\n\r",In1);
} //EOFor
}//EOIf
buf[res]=0;
printf("Received Data is:%s\n\r",buf);
if (res==0)
STOP=TRUE; //stop loop if only a CR was input
wait_flag = TRUE; // wait for new input
}
} //while stop==FALSE
while(readchar)
/* restore old port settings */
tcsetattr(fd,TCSANOW,&oldtio);
close(fd);
}
/************************************************** *************************
* signal handler. sets wait_flag to FALSE, to indicate above loop that *
* characters have been received. *
************************************************** *************************/
void signal_handler_IO (int status)
{
printf("received SIGIO signal.\n");
wait_flag = FALSE;
}
答案 0 :(得分:4)
您不应该使用SIGIO。我从未找到任何使用它做任何事情的好文档,并且有更好的方法。有民意调查,选择和 epoll 系列功能,可以更好地为此工作。在我看来,你的程序正在忙着等待数据变得可用,这意味着它占用了CPU时间。当没有任何事情要做时,替代方案让你的程序进入睡眠状态。您可以使用 pause 来获得此效果,程序将进入睡眠状态,直到收到信号(如SIGIO)。您也可以使用在阻止模式下打开tty文件,让读取阻止您直到读取内容。
您不应该同时使用信号处理程序和常规代码中的printf
。通常,您根本不应该使用信号处理程序中的 stdio 操作,因为它可以休眠,但您通常可以在测试期间使用它。从信号处理程序和常规代码(或多个信号处理程序,如果一个信号没有阻止其他信号)中使用它是不好的,因为那时函数将访问相同的数据。您的常规代码中基本上printf
可能会被SIGIO中断,然后调用printf
,并且printf
都希望访问FILE stdout
的内部数据 - 无论是那个还是锁(用于阻止阻塞不同线程,而不是第二次调用同一个线程)都将阻止 SIGIO 处理程序调用{{1}},这将阻止整个程序。这里的问题被称为竞争条件,可能会或可能不会发生,具体取决于时间。
在代码中:
_
printf
_
即使您已经填充了缓冲区的一部分,也会不断地传递255作为所需的长度。如果您是第一次通过循环,则会获得254个字节的数据,然后再次调用再次请求255个字节并获得超过1个字节的溢出缓冲区。此外,您永远不会将do {
res = read(fd,buf+offset,255);
offset += res;
} while (offset < bytes_expected);
放回offset
,因此它会增长和增长,因此如果您的程序读取的字节数超过255个,则缓冲区溢出。
您也没有检查0
返回值不是-1。如果它是-1那么你的程序会做很糟糕的事情。
此外,没有任何真正的原因(我可以看到)尝试在写入已经读回的数据之前尝试累积255个字节的数据。即使您只想处理串行端口中的前255个字节,您也可以继续写入最后一个,因为最后一个进入,然后在达到255限制后退出循环。
read
中设置一个值,但它有其他字段。这些应该被设置为某种东西,或者你只是将随机位作为标志和掩码投入。 _
struct sigaction saio
_
struct sigaction saio = {0};
saio.sa_handler = signal_handler_IO;
/* Now you don't have to worry about the flags and mask b/c those both are
zeroed out and I'm pretty sure those are decent values for your purposes,
but you could still set them explicitly. */
传递给newtio
,但您可能尚未完全初始化它。你应该做的:_
tcsetattr
在设置其他标志之前。这样,您可以只使用已经存在的值,而不是明确设置的任何字段。
此外,您似乎正在设置所有 BAUDRATE 标志。
tcgetattr(fd,&oldtio); /* save current port settings */
memcpy(&newtio, oldtio, sizeof(struct termios) ); /* !! <-- This line !! */
这很不可能。 /* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
用于屏蔽这样的波特码:
tcflag_t baud_code = tio.c_cflag&amp; BAUDRATE;
现在BAUDRATE
只有与波特集相对应的位,没有设置baud_code
和CRTSCTS
的东西。您应该使用其中一个类似CLOCAL
和B9600
的波特码而不是BAUDRATE,除非您想:
B115200
只会改变波特率并留下其余的标志。这是tcflag_t non_baud_flags = tio.c_cflag | ~BAUDRATE;
tcflag_t new_flags = non_baud_flags | B9600;
的用途。
_
int cfsetspeed(struct termios *termios_p, speed_t speed);
答案 1 :(得分:0)
我不知道你在哪里得到这个代码,但它看起来过于复杂,你实际想要实现的目标。看起来像复制粘贴给我。
像这样的循环有什么问题?
while() {
len = read(serialfd, somebuf, wanted_len);
write to file
}
你的问题究竟是什么?如何找到退出循环的好测试? 在经过一段时间后收到一些字符时,您想退出吗?
关于len的可能值的答案,您可以查看tcgetattr
手册页。
也许你的tty选项不适合你想要实现的目标?
对不起,但你的问题和代码都不清楚,也许你可以先描述你希望用你的程序实现的目标。