9

我有一个模拟键盘的 USB RFID 读卡器。因此,当我将卡放入其中时,我会在终端窗口上看到字符串-即"0684a24bc1"

但我想在我的 C 程序中阅读它。我使用时没有问题:scanf("%s",buff);

但是当我使用下面的代码时,我得到了很多(大约 500 字节)无法识别的数据。为什么?我想要非阻塞读取。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>

int main(int argc, char ** argv) {
  int fd;
  char buf[256];

  fd = open("/dev/input/event3", O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1) {
    perror("open_port: Unable to open /dev/ttyAMA0 - ");
    return(-1);
  }

  // Turn off blocking for reads, use (fd, F_SETFL, FNDELAY) if you want that
  fcntl(fd, F_SETFL, 0);


  }

while(1){
  n = read(fd, (void*)buf, 255);
  if (n < 0) {
    perror("Read failed - ");
    return -1;
  } else if (n == 0) printf("No data on port\n");
  else {
    buf[n] = '\0';
    printf("%i bytes read : %s", n, buf);
  }
sleep(1);
printf("i'm still doing something");

}
  close(fd);
  return 0;
}
4

3 回答 3

13

根据Linux 输入文档第 5 节,/dev/input/eventX 设备返回数据如下:

您可以使用阻塞和非阻塞读取,也可以在 /dev/input/eventX 设备上使用 select(),并且您将始终在读取时获得整数个输入事件。他们的布局是:

struct input_event {
      struct timeval time;
      unsigned short type;
      unsigned short code;
      unsigned int value; };

'time' 是时间戳,它返回事件发生的时间。类型例如 EV_REL 表示相对时间,EV_KEY 表示按键或释放。在 include/linux/input.h 中定义了更多类型。

'code' 是事件代码,例如 REL_X 或 KEY_BACKSPACE,完整的列表在 include/linux/input.h 中。

“价值”是事件携带的价值。EV_REL 的相对变化,EV_ABS(操纵杆...)的绝对新值,或者 EV_KEY 的 0 用于释放,1 用于按键,2 用于自动重复。

于 2013-04-11T12:53:22.697 回答
3
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>

int main(int argc, char *argv[])
{
    int timeout_ms = 5000;
    char input_dev[] = "/dev/input/event17\0";
    int st;
    int ret;
    struct pollfd fds[1];

    fds[0].fd = open(input_dev, O_RDONLY|O_NONBLOCK);

    if(fds[0].fd<0)
    {
        printf("error unable open for reading '%s'\n",input_dev);
        return(0);
    }

    const int input_size = 4096;
    unsigned char input_data[input_size];
    memset(input_data,0,input_size);

    fds[0].events = POLLIN;

    int exit_on_key_press_count = 10;

    while(true)
    {
        ret = poll(fds, 1, timeout_ms);

        if(ret>0)
        {
            if(fds[0].revents)
            {
                ssize_t r = read(fds[0].fd,input_data,input_size);

                if(r<0)
                {
                    printf("error %d\n",(int)r);
                    break;
                }
                else
                {
                    printf("total bytes read %d/%d\n",(int)r,input_size);

                    for(int i = 0; i<r;i++)
                    {
                        printf("%02X ",(unsigned char)input_data[i]);
                    }
                    printf("\n");
                    memset(input_data,0,input_size);

                    exit_on_key_press_count--;
                    if(exit_on_key_press_count<1)
                        break;
                }
            }
            else
            {
                printf("error\n");
            }
        }
        else
        {
            printf("timeout\n");
        }
    }

    close(fds[0].fd);
    return 0;
}

$ sudo ./keypressed

读取的总字节数 72/4096

35 49 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 04 00 04 00 5A 00 07 00 35 49 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 05 01 04 0 0 00 05 01 09 0 0 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 00 00 00 00 00 00 00 00

这是原始数据,要转换为某个键,我需要阅读上面的“Linux 输入文档”链接...

于 2019-05-01T07:32:31.203 回答
-1

您的代码在打开事件设备时显然是错误的/dev/input/。甚至您的错误消息也与选择相矛盾:

perror("open_port: Unable to open /dev/ttyAMA0 - ");

从文件中读取会/dev/input/eventN返回带有事件描述(如指针移动或按钮按下)的二进制数据,而不是文本。您可能想要打开某种串行仿真设备。


10年答题周年编辑

考虑如何在 Unix.SE 上调试来自输入设备 (/dev/input/event*)的输入。

有一个易于使用的内容参考解码器/dev/input/eventN。您可以使用它来验证和比较您的代码。

于 2013-04-11T12:54:27.440 回答