我正在构建一种消耗键盘模拟设备数据的设备驱动程序。
该设备是刷卡,因此其行为如下:
由于我不知道自己会收到多少个字符,因此阻止键盘输入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')
答案 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详细说明了VTIME
和VMIN
的各种可能性。