[英]Failed to read a USB HID RFID-Reader with C
我有一個便宜的USB-RFID閱讀器。 該閱讀器是一個HID鍵盤(無按鈕)。 我需要捕獲閱讀器的輸出而不將其寫入任何控制台。 我在這里找到此代碼: https : //stackoverflow.com/a/7672324/4500123
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <termios.h>
#include <signal.h>
int main(int argc, char* argv[])
{
struct input_event ev[64];
int fevdev = -1;
int result = 0;
int size = sizeof(struct input_event);
int rd;
int value;
char name[256] = "Unknown";
char *device = "/dev/input/event3";
fevdev = open(device, O_RDONLY);
if (fevdev == -1) {
printf("Failed to open event device.\n");
exit(1);
}
result = ioctl(fevdev, EVIOCGNAME(sizeof(name)), name);
printf ("Reading From : %s (%s)\n", device, name);
printf("Getting exclusive access: ");
result = ioctl(fevdev, EVIOCGRAB, 1);
printf("%s\n", (result == 0) ? "SUCCESS" : "FAILURE");
while (1)
{
if ((rd = read(fevdev, ev, size * 64)) < size) {
break;
}
value = ev[0].value;
if (value != ' ' && ev[1].value == 1 && ev[1].type == 1) {
printf ("Code[%d]\n", (ev[1].code));
}
}
printf("Exiting.\n");
result = ioctl(fevdev, EVIOCGRAB, 1);
close(fevdev);
return 0;
}
此代碼應該起作用。 我可以在我的RaspberryPI上運行它,而不會出現問題。 我現在嘗試使此代碼在我的Android平板電腦(帶root)上運行。 但是很多時候我缺少字母或代碼不完整。
如果我寫一個文本文件,所有字母都可以順利傳輸。 但是,用代碼將無法正常工作。
我該怎么辦才能找出問題所在? 是時間問題嗎?
當然,您偶爾會丟失一些事件:您最多讀取64個事件結構,但是假設您得到的恰好是兩個,無論rd
的讀取量如何。
您首先應該驗證自己是否具有完整的輸入事件( (rd % sizeof (struct input_event)) == 0
)。 如果沒有,您肯定會警告用戶,因為這種情況非常罕見(永遠不會發生),然后中止操作。
然后,檢查您收到了多少實際輸入事件。 (這將是rd / sizeof (struct input_event)
。)您不能依賴成對發生的事件,因為即使設備以連續的HID消息報告內核內部時序也會影響事物。 相反,您需要分別檢查每個事件,並檢查閱讀的每個事件。
就個人而言,我建議為此使用有限狀態機 。 讓您的外循環使用整個標識符。 在外部循環中,首先丟棄所有可能開始新標識符的事件以外的所有事件。 在內循環中接收這些標識符,以終止標識符結尾。 為了使內部循環更簡單,我將一次只讀取單個事件。 (每秒最多有一千個事件,所以這里額外的系統調用開銷是完全不相關的。)
我在這里有一個完整的條形碼示例-您的用例幾乎沒有什么區別。 仔細檢查barcode_read()
函數; 它包括一個超時,而不是“掛起”(永遠等待),如果在運行中中斷了新的輸入事件序列(對於條形碼,則是一個數字序列,后跟一個非數字序列)被中斷,例如由於閱讀器故障或一些東西。 我敢肯定,您可以輕松地對其進行修改以適合您的用例。
作為對名義動物的回答的回應,我將代碼更改為:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <termios.h>
#include <signal.h>
#define BARCODE_MAXLEN 1023
size_t barcode_read(int fd,
char *const buffer, const size_t length)
{
size_t len = 0;
int status = ETIMEDOUT;
if (!buffer || length < 2 ) {
//errno = EINVAL;
return (size_t)0;
}
while (1) {
struct input_event ev;
ssize_t n;
int digit;
n = read(fd, &ev, sizeof ev);
if (n == (ssize_t)-1) {
if (errno == EINTR)
continue;
status = errno;
break;
} else
if (n == sizeof ev) {
/* We consider only key presses and autorepeats. */
if (ev.type != EV_KEY || (ev.value != 1 && ev.value != 2))
continue;
switch (ev.code) {
case KEY_0: digit = '0'; break;
case KEY_1: digit = '1'; break;
case KEY_2: digit = '2'; break;
case KEY_3: digit = '3'; break;
case KEY_4: digit = '4'; break;
case KEY_5: digit = '5'; break;
case KEY_6: digit = '6'; break;
case KEY_7: digit = '7'; break;
case KEY_8: digit = '8'; break;
case KEY_9: digit = '9'; break;
default: digit = '\0';
}
/* Non-digit key ends the code, except at beginning of code. */
if (digit == '\0') {
if (!len)
continue;
status = 0;
break;
}
if (len < length)
buffer[len] = digit;
len++;
continue;
} else
if (n == (ssize_t)0) {
status = ENOENT;
break;
} else {
status = EIO;
break;
}
}
/* Add terminator character to buffer. */
if (len + 1 < length)
buffer[len + 1] = '\0';
else
buffer[length - 1] = '\0';
errno = status;
return len;
}
int main(int argc, char* argv[])
{
struct input_event ev[64];
int fevdev = -1;
int result = 0;
int size = sizeof(struct input_event);
int rd;
int value;
char name[256] = "Unknown";
char *device = "/dev/usb/input1-1.4";
fevdev = open(device, O_RDONLY);
if (fevdev == -1) {
printf("Failed to open event device.\n");
exit(1);
}
result = ioctl(fevdev, EVIOCGNAME(sizeof(name)), name);
printf ("Reading From : %s (%s)\n", device, name);
printf("Getting exclusive access: ");
result = ioctl(fevdev, EVIOCGRAB, 1);
printf("%s\n", (result == 0) ? "SUCCESS" : "FAILURE");
while (1) {
char code[BARCODE_MAXLEN + 1];
size_t len;
//if (done) {
// status = EINTR;
// break;
//}
len = barcode_read(fevdev, code, sizeof code);
if (errno) {
//status = errno;
break;
}
if (len < (size_t)1) {
//status = ETIMEDOUT;
break;
}
printf("%zu-digit barcode: %s\n", len, code);
fflush(stdout);
}
printf("Exiting.\n");
result = ioctl(fevdev, EVIOCGRAB, 1);
close(fevdev);
return 0;
}
我真的不知道我在這里做了什么。 (我只是vb.net中的一個業余程序員)本質上,我使用了Nominal Animal(size_t條形碼_read)中的示例並刪除了超時。 這很完美。 沒有更多的讀取錯誤。 當然,這不是一個好的程序風格...但是它對我有用。
非常感謝名義動物對問題的解釋和示例!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.