草庐IT

linux - USB HID OUT 报告 - 哪个端点是正确的?

coder 2023-06-20 原文

我们有一个基于 TI 的 CC2531 的嵌入式设备,它有一个(除了控制 EP0 和一些仅用于 IN 的端点)一个既是 IN 又是 OUT 的端点。我们注意到 Windows 发送 OUT 报告的方式与 Linux 发送报告的方式不同。这实际上困扰了我们很长一段时间,但我们一直无法找到解释。

在我看来,linux 以其应有的方式进行操作:OUT 报告通过与 HID 报告关联的端点传输,正如我们从 libusb 获取的那样:

Item             | Dev | EP | Status | Speed |Payload
-----------------+-----+----+--------+-------+-------------------------------
OUT transaction  | 13  | 4  |  ACK   |  FS   | 64 bytes (90 13 00 00 00 00 ..

另一方面,Windows 通过控制端点 (EP0) 发送它。我们使用setup API 来找到我们需要的usages 的设备,为IN 和OUT 打开它并使用相同的文件描述符进行读写。 EP4 IN 报告通过这个文件描述符很好地接收,但是通过相同的文件描述符写入报告,最终在 EP0 上:

Item               | Dev | EP | Status | Speed |Payload
-------------------+-----+----+--------+-------+-------------------------------
Class request OUT  | 25  | 0  |   OK   |  FS   | 64 bytes (90 13 00 00 00 00 ..

(抱歉,还不能发图片。我手抄了 Ellisys 报告)

嵌入式设备不检查接收到 OUT 报告的 EP(即 EP0 上的 SET 报告将汇集到与处理 HID 事件时在其他端点上发现的 OUT 报告相同的功能),因此它会以任何一种方式响应。

我的问题是:两种方式都正确吗?如果不正确,哪个正确,哪个不正确?会不会是我们的描述符中的错误在 Windows 上触发了这种行为?

为了完整起见:这是我们的描述符:http://tny.cz/ac745a8f (从供应商标识中删除以让我的老板高兴 :) )

在 Windows 上放大报告:(高兴!我现在可以拍照了 :) )

整个交易:

Windows 上使用的库:hid.lib、hidclass.lib 和 setupapi.lib。在编写报告时,我们使用函数 HidP_SetUsageValueArray 和 HidD_SetOutputReport。 PHIDP_PREPARSED_DATA 和 HIDP_CAPS 可通过函数 HidD_GetAttributes、HidD_GetPreparsedData 和 HidP_GetCaps 找到。使用 SetupDiEnumDeviceInterfaces 找到设备的文件路径。如果我们找到具有正确 VID、PID、caps.UsagePage 和 caps.Usage 的设备,那就是我们使用的设备。

在 Linux 上它有点棘手,因为我不是实现 Linux 代码的人。我可以说的是使用了 libusb-1.0.9,使用 libusb_open_device_with_vid_pid 打开设备,使用 libusb_fill_interrupt_transfer 和 libusb_submit_transfer 发送报告。我看到 libuwand_fill_interrupt_transfer 接受一个端点作为参数,所以我认为只要使用 libusb_open_device_with_vid_pid 的句柄并将正确的参数作为端点传递,libusb 就会确定将报告放在哪里。

最佳答案

我想我找到了答案。

纯属巧合,我偶然发现了 Keil 论坛,在那里我找到了这样的语句“HidD_SetOutputReport 将使用控制端点,如果您希望它通过另一个端点,请使用 WriteFile”。我知道 5 年多前我曾尝试过那条路,但我陷入了具有重叠结构的异步 IO 中。因为看起来我有出路(使用 HidD_SetOutputReport),所以我放弃了 WriteFile 路径。所以现在是时候再次寻求那条道路了,我做到了。代码:

res = HidD_SetOutputReport(m_DeviceControl[dev], report, m_CapsControl[dev].OutputReportByteLength);

已被替换为

                DWORD bytesWritten;
                OVERLAPPED eventWrite = {0};

                eventWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

                int rv3 = WriteFile(m_DeviceControl[dev], report, m_CapsControl[dev].OutputReportByteLength, &bytesWritten, &eventWrite);
                if (rv3 == 0)
                {
                    int err = GetLastError();

                    if (err == ERROR_IO_PENDING)
                    {
                        bool done = false;

                        do
                        {
                            // yes. Wait till pending state has gone
                            rv3 = WaitForSingleObject(eventWrite.hEvent, 25);
                            if (rv3 == WAIT_OBJECT_0)
                            {
                                GetOverlappedResult(m_DeviceControl[dev], &eventWrite, &bytesWritten, FALSE);
                                done = true;
                                res = TRUE;
                            }
                            else if (rv3 == WAIT_TIMEOUT)
                            {
                                // Need to try again.
                            }
                            else
                            {
                                m_StoppingControlOut = true;
                                done = true;
                            }
                        }
                        while (!done && !m_StoppingControlOut);
                    }
                }
            }

这使得请求通过正确的端点。

因此我得出以下结论:

  • 我认为 HID 设备解释通过控制端点发送的 OUT 报告是错误的。
  • 正确使用 WriteFile(使用重叠 IO)使 OUT 报告使用正确的端点。

关于linux - USB HID OUT 报告 - 哪个端点是正确的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28428776/

有关linux - USB HID OUT 报告 - 哪个端点是正确的?的更多相关文章

  1. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  2. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

    question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

  3. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

  4. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  5. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  6. 报告回顾丨模型进化狂飙,DetectGPT能否识别最新模型生成结果? - 2

    导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri

  7. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  8. ruby - 如何在 RVM 下将 Bundler 安装到 @global gemset,这是正确的方法吗 - 2

    我在OSX上(如果重要的话)。如果我使用RVM安装Ruby,它会默认将Bundler安装到@globalgemset假设我想要一个不同版本的bundler。我假设我需要做的就是执行geminstallbundler--version但是,这会将bundler安装到默认gemset并且RVM不会为其设置路径。因此,如果我键入bundler,它仍会启动一个与Ruby一起安装到@global中的bundler两个问题:如何将bundler安装到@globalgemset。将bundler安装到@globalgemset中的模式是否正确,或者我遗漏了什么 最佳答案

  9. ruby-on-rails - 如何正确格式化字符串,如 'mccdougal' 到 'McDougal' - 2

    什么Ruby或RailsDSL会将字符串"mccdougal"格式化为"McDougal",同时留下字符串"McDougal"原样?将titleize传递给"McDougal"结果如下:"McDougal".titleize#=>"McDougal" 最佳答案 据我所知,没有可以处理这种情况的Rails助手。这是一个非标准的边缘案例,需要特殊处理。但是,您可以创建自定义字符串变形。您可以将这段代码放入初始化程序中:ActiveSupport::Inflector.inflections(:en)do|inflect|inflect.

  10. ruby - 使用哪个,eruby 还是 erb? - 2

    eruby和erb有什么区别?哪些考虑因素会促使我选择其中之一?我的应用程序正在为网络设备(路由器、负载平衡器、防火墙等)生成配置文件。我的计划是对配置文件进行模板化,在源文件中使用嵌入式ruby​​(通过eruby或erb)来执行诸如迭代生成路由器的所有接口(interface)配置block之类的操作(这些block都非常相似,仅在标签上有所不同和IP地址)。例如,我可能有这样一个配置模板文件:hostnamesample-routerlogging10.5.16.26当通过嵌入式ruby​​解释器(erb或eruby)运行时,会产生以下输出:hostnamesample-rout

随机推荐