在 Linux 上使用 libudev 阻止读取的问题

发布于 2024-08-30 21:03:53 字数 2912 浏览 1 评论 0原文

我们使用以下例程(在 Linux 上,使用 libudev)从配置为 USB HID 设备的 PIC 微控制器读取数据。仅当按下或释放连接到 PIC 单片机的按钮时才会发送数据。

该例程缺少来自 PIC 控制器的消息,我怀疑这是因为下面对 poll 的调用没有按其应有的方式运行。

在读取第一条消息之前,对 poll 的调用将可靠地阻塞 1 秒。一旦读取到第一条消息,对 poll 的调用就会立即返回,而不是像应有的那样阻塞 1 秒(1000 毫秒)。

我通过在每次读取后关闭并重新打开设备来解决这个问题。这使得轮询行为正确,但我认为关闭并重新打开设备可能是丢失消息的原因。

bool PicIo::Receive (unsigned char* picData, const size_t picDataSize) {

    static hiddev_report_info     hidReportInfo;
    static hiddev_usage_ref_multi hidUsageRef;

    if (-1 == PicDeviceDescriptor()) {
        return false;
    }

    // Determine whether or not there is data available to be read
    pollfd pollFd;

    pollFd.fd = PicDeviceDescriptor();
    pollFd.events = POLLIN;

    int dataPending = poll (&pollFd, 1, 1000);

    if (dataPending <= 0) {
        return false;
    }  


    // Initialize the HID Report structure for an input report
    hidReportInfo.report_type = HID_REPORT_TYPE_INPUT;
    hidReportInfo.report_id   = 0;
    hidReportInfo.num_fields  = 64;

    if (-1 == ioctl(PicDeviceDescriptor(), HIDIOCGREPORT, &hidReportInfo)) {
        return false;
    }

    // Initizlize the HID Usage Reference for an Input report
    hidUsageRef.uref.report_type = HID_REPORT_TYPE_INPUT;
    hidUsageRef.uref.report_id   = 0;
    hidUsageRef.uref.field_index = 0;
    hidUsageRef.uref.usage_index = 0;
    hidUsageRef.num_values       = 64;

    if (-1 == ioctl(PicDeviceDescriptor(), HIDIOCGUSAGES, &hidUsageRef)) {
        return false;
    }

    // Transfer bytes from the usage report into the return value.
    for (size_t idx=0; (idx < 64) && (idx < picDataSize); ++idx) {
        picData[idx] = hidUsageRef.values[idx];
    }

    return true;
}

函数 PicDeviceDescriptor() 检查设备以确保它存在。以下是 PicDeviceDescriptor 函数的相关详细信息,显示了如何开始打开设备。

int PicIo::PicDeviceDescriptor(int command) {

    struct stat     statInfo;
    static int      picDeviceDescriptor = -1;
    string          picDevicePath       = "/dev/usb/hiddev0";

    if ((-1 != picDeviceDescriptor) && (CLOSE == command)) {
        close (picDeviceDescriptor);
        picDeviceDescriptor = -1;
    } else if ((-1 != picDeviceDescriptor) && (-1 == fstat(picDeviceDescriptor, &statInfo))) {
        // Handle the case where the PIC device had previously been detected, and
        // is now disconnected.
        close (picDeviceDescriptor);
        picDeviceDescriptor = -1;
    } else if ((-1 == picDeviceDescriptor) && (m_picDevice.IsConnected())) {
        // Create the PIC device descriptor if the PIC device is present (i.e. its 
        // device node is present) and if the descriptor does not already exist
        picDeviceDescriptor = open (picDevicePath.c_str(), O_RDONLY);
    }

    return picDeviceDescriptor;
}

我确信我做错了什么,但我用谷歌搜索了这个问题,似乎找不到任何相关的答案。任何帮助将非常感激 - 谢谢。

We are using the following routine (on Linux, with libudev) to read data from a PIC microcontroller configured as a USB HID device. The data is sent only when a button connected to the PIC microcontroller is pressed or released.

The routine is missing messages from the PIC controller, and I suspect that this is because the call to poll below is not behaving as it should.

The call to poll will reliably block for 1 second util the first message is read. As soon as the first message is read, the call to poll returns immediately instead of blocking for 1 second (1000 milliseconds) like it should.

I have worked around this problem by closing and re-opening the device after each read. This makes poll behave correctly, but I think that closing and re-opening the device may be the reason for the lost messages.

bool PicIo::Receive (unsigned char* picData, const size_t picDataSize) {

    static hiddev_report_info     hidReportInfo;
    static hiddev_usage_ref_multi hidUsageRef;

    if (-1 == PicDeviceDescriptor()) {
        return false;
    }

    // Determine whether or not there is data available to be read
    pollfd pollFd;

    pollFd.fd = PicDeviceDescriptor();
    pollFd.events = POLLIN;

    int dataPending = poll (&pollFd, 1, 1000);

    if (dataPending <= 0) {
        return false;
    }  


    // Initialize the HID Report structure for an input report
    hidReportInfo.report_type = HID_REPORT_TYPE_INPUT;
    hidReportInfo.report_id   = 0;
    hidReportInfo.num_fields  = 64;

    if (-1 == ioctl(PicDeviceDescriptor(), HIDIOCGREPORT, &hidReportInfo)) {
        return false;
    }

    // Initizlize the HID Usage Reference for an Input report
    hidUsageRef.uref.report_type = HID_REPORT_TYPE_INPUT;
    hidUsageRef.uref.report_id   = 0;
    hidUsageRef.uref.field_index = 0;
    hidUsageRef.uref.usage_index = 0;
    hidUsageRef.num_values       = 64;

    if (-1 == ioctl(PicDeviceDescriptor(), HIDIOCGUSAGES, &hidUsageRef)) {
        return false;
    }

    // Transfer bytes from the usage report into the return value.
    for (size_t idx=0; (idx < 64) && (idx < picDataSize); ++idx) {
        picData[idx] = hidUsageRef.values[idx];
    }

    return true;
}

The function PicDeviceDescriptor() does checking on the device to make sure that it is present. Here are the pertinent details of the PicDeviceDescriptor function, showing how the device is begin opened.

int PicIo::PicDeviceDescriptor(int command) {

    struct stat     statInfo;
    static int      picDeviceDescriptor = -1;
    string          picDevicePath       = "/dev/usb/hiddev0";

    if ((-1 != picDeviceDescriptor) && (CLOSE == command)) {
        close (picDeviceDescriptor);
        picDeviceDescriptor = -1;
    } else if ((-1 != picDeviceDescriptor) && (-1 == fstat(picDeviceDescriptor, &statInfo))) {
        // Handle the case where the PIC device had previously been detected, and
        // is now disconnected.
        close (picDeviceDescriptor);
        picDeviceDescriptor = -1;
    } else if ((-1 == picDeviceDescriptor) && (m_picDevice.IsConnected())) {
        // Create the PIC device descriptor if the PIC device is present (i.e. its 
        // device node is present) and if the descriptor does not already exist
        picDeviceDescriptor = open (picDevicePath.c_str(), O_RDONLY);
    }

    return picDeviceDescriptor;
}

I'm sure that I'm doing something wrong, but I've Googled the issue and cannot seem to find any relevant answers. Any help would be very much appreciated -- Thx.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心如狂蝶 2024-09-06 21:03:53

poll 继续指示文件描述符可读的原因是您从未对其进行read()ioctl() 不算作 read()。据推测,设备会提供一些数据可供读取 - 即使它只是唤醒用户空间进程的虚拟值。

The reason that poll is continuing to indicate that the file descriptor is readable is that you never read() from it. ioctl() does not count as read(). Presumably the device makes some data available to read - even if it's only a dummy value to wake the userspace process.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文