使用“定义_GNU_SOURCE”时的printf替代方法

时间:2019-06-30 15:47:22

标签: serial-port printf flags corrupt termios

在阅读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;
  }

1 个答案:

答案 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