簡體   English   中英

無法讀取帶有C的USB HID RFID讀取器

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM