ubuntu上的键盘模拟器设备行为

时间:2017-08-07 18:00:08

标签: ruby device-driver

我正在构建一种消耗键盘模拟设备数据的设备驱动程序。

该设备是刷卡,因此其行为如下:

  • 用户走了,刷卡
  • 我得到一串字符(键码,真的,包括大写字母的修饰键)
  • 我不知道我将会有多少角色
  • 我不知道什么时候能得到什么

由于我不知道自己会收到多少个字符,因此阻止键盘输入tty并不是很有用 - 我会在最后一个字符后结束阻塞。我在Ruby中使用IO模块对键盘设备执行异步读取,并使用超时来确定是否已到达数据末尾。这在逻辑上可以正常工作(即使用户快速刷卡他或她的卡也会比人物之间的发送速度慢)。

问题是,有时候,我会丢失字符串中间的数据。我的预感是发生了某种缓冲区溢出,因为我读取的数据太慢了。为了确认这一点,我在每个关键进程之间插入了小等待。更长的等待时间(20ms +)确实会加剧这个问题。然而,等待大约5ms实际上会让它消失?我能想到的唯一解释是异步读取本身很昂贵(因为Ruby),而没有速率限制的情况实际上比使用 5ms延迟更慢。

听起来合理吗?关于这可能是什么还有其他想法吗?

ruby​​实际上是JRuby 9000.该机器是Ubuntu LTS 16。

编辑:这里是相关代码的片段

  private def read_swipe(buffer_size, card_reader_input, pause_between_reads, seconds_to_complete)
    limit = Time.now + seconds_to_complete.seconds
    swipe_data = ''
    begin
      start_time = Time.now
      sleep pause_between_reads
      batch = card_reader_input.read_nonblock(buffer_size)
      swipe_data << batch
    rescue IO::WaitReadable
      IO.select([card_reader_input], nil, nil, 0.5)
      retry unless limit < start_time
    end while start_time < limit
    swipe_data
  end

其中card_reader_input = File.new(event_handle, 'rb')

1 个答案:

答案 0 :(得分:0)

我不确定Ruby代码,但您可以使用linux sysfs来访问键盘'like'设备中出现的字符,如果可行,您可以从ruby应用程序调用{​​{1}}代码。我为条形码阅读器做了这个,以下是代码:

C

现在你不知道要获得多少个角色,你可以使用static int init_barcode_com(char* bcr_portname) { int fd; /* Open the file descriptor in non-blocking mode */ fd = open(bcr_portname, O_RDONLY | O_NOCTTY | O_NDELAY); cout << "Barcode Reader FD: " << fd <<endl; if (fd == -1) { cerr << "ERROR: Cannot open fd for barcode communication with error " << fd <<endl; } fcntl(fd, F_SETFL, 0); /* Set up the control structure */ struct termios toptions; /* Get currently set options for the tty */ tcgetattr(fd, &toptions); /* Set custom options */ /* 9600 baud */ cfsetispeed(&toptions, B9600); cfsetospeed(&toptions, B9600); /* 8 bits, no parity, no stop bits */ toptions.c_cflag &= ~PARENB; toptions.c_cflag &= ~CSTOPB; toptions.c_cflag &= ~CSIZE; toptions.c_cflag |= CS8; /* no hardware flow control */ toptions.c_cflag &= ~CRTSCTS; /* enable receiver, ignore status lines */ toptions.c_cflag |= CREAD | CLOCAL; /* disable input/output flow control, disable restart chars */ toptions.c_iflag &= ~(IXON | IXOFF | IXANY); /* disable canonical input, disable echo, * disable visually erase chars, * disable terminal-generated signals */ toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* disable output processing */ toptions.c_oflag &= ~OPOST; /* wait for n (in our case its 1) characters to come in before read returns */ /* WARNING! THIS CAUSES THE read() TO BLOCK UNTIL ALL */ /* CHARACTERS HAVE COME IN! */ toptions.c_cc[VMIN] = 0; /* no minimum time to wait before read returns */ toptions.c_cc[VTIME] = 100; /* commit the options */ tcsetattr(fd, TCSANOW, &toptions); /* Wait for the Barcode to reset */ usleep(10*1000); return fd; } static int read_from_barcode_reader(int fd, char* bcr_buf) { int i = 0, nbytes = 0; char buf[1]; /* Flush anything already in the serial buffer */ tcflush(fd, TCIFLUSH); while (1) { nbytes = read(fd, buf, 1); // read a char at a time if (nbytes == -1) { return -1; // Couldn't read } if (nbytes == 0) { return 0; } if (buf[0] == '\n' || buf[0] == '\r') { return 0; } bcr_buf[i] = buf[0]; i++; } return 0; } VMIN组合来解决你的问题。此document详细说明了VTIMEVMIN的各种可能性。