Linux 串行读取抛出错误
Linux Serial Read throws Error
我正在尝试使用以下 C 代码从我的串口读取数据。我可以成功地写入正在监听的计算机(耶!)但是读取会抛出错误(代码 11 - 资源暂时不可用)。我还注意到我的 messages/dmesg 日志没有任何关于故障等的信息。这样就好了。
//A bunch of INCLUDES exist here....the the code
int fd=0;
int status=0;
int running=1;
char buffer[100];
char message[7];
void main(){
fd = 1;
fd=open("/dev/ttyM0",O_RDWR | O_NOCTTY);
if(fd == -1)
{
perror("open_port: Unable to open /dev/ttys0");
}
else
{
while(running<20)
{
sprintf(message,"Test%d\r",running);
status=write(fd,message,6);
if(status<0)
{
printf("Error Writing. Status=%d\n %s\n",errno, strerror(errno));
}
status=read(fd,buffer,8); //This throws an error(11). My connected device is writing "Testing/r"
if(status<0)
{
printf("Error Reading. Status=%d \n%s\n",errno, strerror(errno));
//close(fd);
running=running+1;
}
else
{
printf("%s\n\r",buffer);
}
sleep(2);
}
close(fd);
}
} //END MAIN
这些是我的端口串行设置。我正在尝试 read/write 在 9600 8 位,无奇偶校验,1 个停止位。我认为我的设置是正确的。
sudo stty -a -F /dev/ttyM0
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany
-imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
非常感谢任何帮助。谢谢!
这里有缓冲区溢出:
sprintf(message,"Test%d\r",running);
因为 message
声明为:
char message[6];
message
如果要容纳 6 个字符的字符串,则它的大小至少需要 7 个字符,因为需要 '[=14=]'
终止符。
可能还有其他问题,但您应该解决这个问题,看看是否有任何不同。
您在 open
调用中使用了 O_NDELAY
选项。这使得文件描述符 非阻塞 。这意味着如果您执行 read
并且没有可用数据,则 read
调用将 return EAGAIN
这就是您看到的错误。
目前,您可以从 open
中删除 O_NDELAY
。将来,您可能应该再次使其成为非阻塞的,并使用 select
或 poll
来确定何时可以读取。
With O_NDELAY gone the program just sits there waiting for input
看起来 termios 是针对规范输入设置的(基于 stty[=35= 中的 icanon ] 输出)。在规范(又名熟)模式下,从串行端口接收的字符在使用 read() 提供给用户程序之前进行处理。
根据 Linux 手册页:
In canonical mode:
- Input is made available line by line. An input line is available
when one of the line delimiters is typed (NL, EOL, EOL2; or EOF at
the start of line). Except in the case of EOF, the line delimiter
is included in the buffer returned by read(2).
您的 termios 也设置了 icrnl,这意味着回车符 return 在输入时被转换为换行符(除非igncr 已设置,这不是因为它前面有一个连字符)。 eol 和 eol2 都是未定义的(默认值)。
因此,对于您的设置,行尾定义为换行符或回车 return(或行首的 cntl-D)。验证您的远程设备是否确实发送了 CR 或 LF 控制字符来终止线路。您在代码中的评论表明它不是(即“/r”不是回车 return)。
要正确使用由 read() 编辑的文本 return 作为字符串,请将请求设置为小于分配的缓冲区大小(以确保空间附加一个空终止符)。然后在好的return之后,使用returned字节数作为索引来存储字符串终止符。
status = read(fd, buffer, sizeof(buffer) - 1);
if (status < 0) {
/* handle error condition */
} else {
buffer[status] = '[=10=]';
printf("%s\n\r", buffer);
}
我正在尝试使用以下 C 代码从我的串口读取数据。我可以成功地写入正在监听的计算机(耶!)但是读取会抛出错误(代码 11 - 资源暂时不可用)。我还注意到我的 messages/dmesg 日志没有任何关于故障等的信息。这样就好了。
//A bunch of INCLUDES exist here....the the code
int fd=0;
int status=0;
int running=1;
char buffer[100];
char message[7];
void main(){
fd = 1;
fd=open("/dev/ttyM0",O_RDWR | O_NOCTTY);
if(fd == -1)
{
perror("open_port: Unable to open /dev/ttys0");
}
else
{
while(running<20)
{
sprintf(message,"Test%d\r",running);
status=write(fd,message,6);
if(status<0)
{
printf("Error Writing. Status=%d\n %s\n",errno, strerror(errno));
}
status=read(fd,buffer,8); //This throws an error(11). My connected device is writing "Testing/r"
if(status<0)
{
printf("Error Reading. Status=%d \n%s\n",errno, strerror(errno));
//close(fd);
running=running+1;
}
else
{
printf("%s\n\r",buffer);
}
sleep(2);
}
close(fd);
}
} //END MAIN
这些是我的端口串行设置。我正在尝试 read/write 在 9600 8 位,无奇偶校验,1 个停止位。我认为我的设置是正确的。
sudo stty -a -F /dev/ttyM0
speed 9600 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany
-imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
非常感谢任何帮助。谢谢!
这里有缓冲区溢出:
sprintf(message,"Test%d\r",running);
因为 message
声明为:
char message[6];
message
如果要容纳 6 个字符的字符串,则它的大小至少需要 7 个字符,因为需要 '[=14=]'
终止符。
可能还有其他问题,但您应该解决这个问题,看看是否有任何不同。
您在 open
调用中使用了 O_NDELAY
选项。这使得文件描述符 非阻塞 。这意味着如果您执行 read
并且没有可用数据,则 read
调用将 return EAGAIN
这就是您看到的错误。
目前,您可以从 open
中删除 O_NDELAY
。将来,您可能应该再次使其成为非阻塞的,并使用 select
或 poll
来确定何时可以读取。
With O_NDELAY gone the program just sits there waiting for input
看起来 termios 是针对规范输入设置的(基于 stty[=35= 中的 icanon ] 输出)。在规范(又名熟)模式下,从串行端口接收的字符在使用 read() 提供给用户程序之前进行处理。
根据 Linux 手册页:
In canonical mode:
- Input is made available line by line. An input line is available when one of the line delimiters is typed (NL, EOL, EOL2; or EOF at the start of line). Except in the case of EOF, the line delimiter is included in the buffer returned by read(2).
您的 termios 也设置了 icrnl,这意味着回车符 return 在输入时被转换为换行符(除非igncr 已设置,这不是因为它前面有一个连字符)。 eol 和 eol2 都是未定义的(默认值)。
因此,对于您的设置,行尾定义为换行符或回车 return(或行首的 cntl-D)。验证您的远程设备是否确实发送了 CR 或 LF 控制字符来终止线路。您在代码中的评论表明它不是(即“/r”不是回车 return)。
要正确使用由 read() 编辑的文本 return 作为字符串,请将请求设置为小于分配的缓冲区大小(以确保空间附加一个空终止符)。然后在好的return之后,使用returned字节数作为索引来存储字符串终止符。
status = read(fd, buffer, sizeof(buffer) - 1);
if (status < 0) {
/* handle error condition */
} else {
buffer[status] = '[=10=]';
printf("%s\n\r", buffer);
}