2017-08-07 46 views
0

我正在構建一個從鍵盤仿真設備中消耗數據的設備驅動程序。ubuntu上的鍵盤模擬器設備行爲

該設備是刷卡,所以其行爲如下:

  • 用戶走向,揮筆卡
  • 我得到字符(鍵碼的字符串,真的,包括對資本修改鍵字母)
  • 我不知道我有多少個字符會得到
  • 當我得到我不知道的東西

因爲我不知道我會得到多少個字符,所以在鍵盤上阻止讀取tty沒有用 - 我最終會在最後一個字符後阻止。我正在做的是,在Ruby中,使用IO模塊對鍵盤設備執行異步讀取,並使用超時確定數據已到達。這在邏輯上工作正常(甚至用戶快速刷卡他/她的卡將比字符之間的發送速率慢)。

問題是,我有時會丟失字符串中間的數據。我的直覺是發生了某種緩衝區溢出,因爲我讀取的數據太慢了。試圖證實這一點,我在每個關鍵流程之間插入了小的等待。較長的等待時間(20ms +)會加劇問題。然而,等待約5ms實際上會讓它消失?我能想出的唯一解釋是異步讀取本身是昂貴的(因爲Ruby),並且在沒有速率限制的情況下執行它實際上比它們以延遲5ms要慢。

這聽起來合理嗎?有關於這可能是什麼的其他想法?

紅寶石實際上是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

@maxpleaner done – kolosy

回答

0

我不知道關於Ruby代碼,但您可以使用linux sysfs來訪問鍵盤「喜歡」設備中出現的字符,如果可行,您可以撥打C來自ruby應用程序的代碼lication。我做了這個條形碼讀取和下面的代碼:

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; 
} 

既然你不知道你要去多少個字符,讓你可以使用VMINVTIME組合來解決您的問題。 document詳細說明VMINVTIME的各種可能性。