在阅读https://www.quora.com/How-can-I-bypass-the-OS-buffering-during-I-O-in-Linux之后,我想尝试使用O_DIRECT选项访问串行端口上的数据,但是似乎可以做到的唯一方法是添加GNU_SOURCE定义,但是当我尝试执行该程序时,屏幕上什么也不会打印。
如果删除“ #define _GNU_SOURCE”并进行编译,则系统在O_DIRECT上给我一个错误。
如果删除了define和O_DIRECT标志,则始终会读取不正确(可能已过时)的数据,但数据会打印在屏幕上。
我仍然想使用O_DIRECT标志并能够查看数据,所以我觉得我需要给printf和朋友一个替代命令,但我不知道如何继续。
我附上了以下代码:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <termios.h>
#define TIMEOUT 5
int main(){
char inb[3]; //our byte buffer
int nread=0; //number bytes read from port
int n; //counter
int iosz=128; //Lets get 128 bytes
int fd=open("/dev/ttyS0", O_NOCTTY | O_RDONLY | O_SYNC | O_DIRECT); //Open port
tcflush(fd,TCIOFLUSH);
for(n=0;n<iosz;n++){
int s=time(NULL); //Start timer for 5 seconds
while (time(NULL)-s < TIMEOUT && nread < 1){
inb[0]='A'; //Fill buffer with bad data
inb[1]='B';
inb[2]='C';
nread=read(fd,(char*)inb,1); //Read ONE byte
tcflush(fd,TCIOFLUSH);
if (nread < 0 || time(NULL)-s >= TIMEOUT){
close(fd); //Exit if read error or timeout
return -1;
}
}
printf("%x:%d ",inb[0] & 0xFF,nread); //Print byte as we receive it
}
close(fd); //program ends so close and exit
printf("\n"); //Print byte as we receive it
return 0;
}
答案 0 :(得分:0)
首先,我不是这个主题的专家,只是对此感到好奇,因此请捏一点盐来回答这个问题。
我不知道您是否打算在这里做什么(如果我不是以错误的方式看待它,那就好像是绕过内核并直接从端口读取到用户空间)是否可能(您可以找到一些示例,例如this one,但我找不到正确记录的任何内容),但是对于最新的内核,您应该在运行代码时遇到错误,但并没有捕获到它。
如果在声明端口后添加以下行:
...
int fd=open("/dev/ttyS0", O_NOCTTY | O_RDONLY | O_SYNC | O_DIRECT );
if (fd == -1) {
fprintf(stderr, "Error %d opening SERIALPORT : %s\n", errno, strerror(errno));
return 1;
}
tcflush(fd,TCIOFLUSH);
....
当您尝试运行时,您会得到:Error 22 opening SERIALPORT : Invalid argument
以我的谦逊和有限的理解,您应该能够将termios的设置更改为raw
,获得相同的效果,这应该是这样的:
struct termios t;
tcgetattr(fd, &t); /* get current port state */
cfmakeraw(&t); /* set port state to raw */
tcsetattr(fd, TCSAFLUSH, &t); /* set updated port state */
有很多关于termios的资料,但是我能找到的唯一一个地方是O_DIRECT
(对于文件)是this one。