首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用WinUSB?

如何使用WinUSB?
EN

Stack Overflow用户
提问于 2016-08-11 22:09:33
回答 4查看 14.3K关注 0票数 8

这是我上一个问题的后续,需要为USB外围设备编写驱动程序吗?

背景

我正在设计一个使用STM32微控制器(裸金属/无操作系统)的USB外围设备。该设备偶尔会连接到Windows,并在每个方向传输几KB的数据。将有一个自定义PC应用程序来控制数据传输,使用专有协议(即USB有效载荷)。

PC将永远是主(启动器)-它将发送命令,设备将发出响应,多达几百字节的数据在一个单一的命令或响应中向任意方向移动。我想我会想要使用USB批量传输模式。

选项1- USB CDC

据我所知,一个选择是我可以使用USB通信设备类(CDC)。在设备端,我可以为USB使用ST的示例代码,例如来自STM32Cube的示例代码。在PC端,该设备将呈现为虚拟COM端口(VCP)。然后,在软件中,我基本上有一个原始的双向流,在这个流之上,我必须定义我的消息格式、命令等等。

  1. 我解释得对吗?

备选方案2- WinUSB

我很难想清楚这到底是什么,以及如何处理它。

  1. WinUSB与USB设备类的关系是什么?它似乎是一个“通用”的USB类,但是我找不到任何说明它的文档。
  2. WinUSB是否提供任何内置的消息分隔符?例如,WritePipe是否将缓冲区的内容作为原子单元发送到设备上?还是像VCP/UART那样得到原始流?
  3. 如何在设备上实现WinUSB?有可用的示例代码吗?(最好是STM32.)

选择

  1. 在选择我的应用程序的选项1和2时,有哪些相关的考虑因素?
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-08-12 04:11:50

  1. 是的,你正确地描述了南加州疾病预防控制中心。
  2. WinUSB的存在是为了支持没有特定设备类的设备。如果您的设备实现了诸如Human设备、海量存储设备或通信设备(CDC)等设备类,则可以只使用操作系统附带的驱动程序与该设备进行通信。如果您想要一个更可定制和灵活的USB接口,不符合其中一个类,您可以使用WinUSB与您的设备对话。你也可以写你自己的驱动,如果你想,但这将是一个很大的工作,我不推荐它。有些人编写了替代WinUSB的驱动程序:您可以查找libusbK、libusb0.sys和UsbDK作为示例。WinUSB具有Windows附带的优点,所以我不会使用其他驱动程序之一,除非它有您真正需要的特定功能。
  3. 我相信WinUSB_WritePipe以单一的USB传输方式发送数据。在USB规范中,传输具有特定的定义。您可以知道传输何时结束,因为您将在传输结束时得到一个短数据包。短数据包是小于端点的最大数据包大小的数据包,它可能是零长度。但是,您应该再次检查这是否是真的;尝试发送一个最大数据包大小倍数的传输,并确保Windows在该传输结束时发送一个零长度数据包。顺便说一句,您应该考虑在端点0上将数据作为控件传输或一系列控件传输发送。控制权转移有一个内置的请求概念和对请求的响应。尽管名称,控制传输可以用来传输大量的数据;它们通常在USB引导程序中使用(参见DFU类)。使用控制传输而不是非零端点的另一个优点是,您不必在固件中添加额外的端点描述符并初始化端点。您的USB堆栈应该有处理自定义控制传输的机器,并且您应该能够通过编写一些回调函数来进行自定义控制传输。
  4. 要在设备端实现WinUSB,您需要编写自己的USB描述符,然后使用低级USB传输命令从端点读取和写入数据,或者处理端点0上特定供应商的控制传输。我不熟悉STM32的USB库,但是您应该能够识别实现控制传输和进出端点的核心组件,而不需要对设备类做任何特定的操作。这是您需要学习如何使用的组件。
  5. 默认情况下,您应该使用WinUSB而不是USB。使用USB的唯一原因是如果您的设备实际上是一个串口,或者您想让人们更容易地使用各种编程语言和环境与您的设备对话。大多数编程语言都支持串行端口,但是用户仍然需要在生成特定命令格式的基础上编写代码,因此它实际上并没有给您带来那么多。USB的一个问题是,如果设备在打开手柄时断开连接,然后重新连接,那么各种USB CDC ACM驱动程序往往会陷入糟糕的状态。特别是,Windows 10之前的usbser.sys不能很好地处理这个问题,您通常需要拔出并回复设备,以使COM端口再次可用。USB使用批量端点进行数据传输,因此没有延迟保证。使用WinUSB时,您可以选择使用中断端点,这样您就可以保证始终为每个USB帧传输一个数据包。
票数 8
EN

Stack Overflow用户

发布于 2018-02-18 00:45:07

WinUSB由两部分组成:

  • WinUsb.sys是一个内核模式的驱动程序,可以作为过滤器或函数驱动程序安装,位于USB设备内核模式设备堆栈中的协议驱动程序之上。
  • WinUsb.dll是公开WinUSB API的用户模式DLL .当WinUsb.sys作为设备的功能驱动程序安装时,应用程序可以使用该API与其通信。WinUSB API-由WinUSB.dll公开。WinUSB以WinUSBCoInstaller.dll的形式包含在Windows (WDK)中,它位于WinDDK\BuildNumber\Redist\Winusb中。

要在应用程序中使用WinUSB API,请执行以下操作:

  • 包括WinUsb.h
  • 将WinUsb.lib添加到链接到应用程序的库列表中。
  • Usb100.h包含一些有用宏的声明。
  • 使用设备接口GUID获取设备路径。正确的GUID是您在用于安装WinUsb.sys的INF中指定的GUID。
  • 通过将您在INF中定义的设备接口GUID传递给SetupDiGetClassDevs,获取设备信息集的句柄。函数返回一个HDEVINFO句柄。
  • 调用SetupDiEnumDeviceInterfaces来枚举系统的设备接口并获取有关设备接口的信息。
  • 调用SetupDiGetDeviceInterfaceDetail获取设备接口的详细数据。
  • 调用GetDevicePath函数以获得设备路径。
  • 将设备路径传递给CreateFile以获得设备的文件句柄。使用ReadFile和WriteFile与设备通信。
  • 将文件句柄传递给WinUsb_Initialize以初始化WinUSB并获得WinUSB句柄。在调用WinUSB API函数时,可以使用设备的WinUSB句柄来标识设备,而不是设备的文件句柄。

对于更高级的解决方案--使用函数:

  • WinUsb_QueryDeviceInformation以获得设备的速度。
  • WinUsb_QueryInterfaceSettings以获得相应的接口描述符。WinUSB句柄对应于第一个接口。
  • WinUsb_QueryPipe获取有关每个端点的信息。
  • WinUsb_WritePipe将缓冲区写入设备默认行为:零长度写入在堆栈中转发.如果传输长度大于最大传输长度,则WinUSB将请求划分为最大传输长度的较小请求,并依次提交请求。
  • 更多功能和信息:howto.docx

出于调试目的,您可能需要: winusbtrace_tool https://blogs.msdn.microsoft.com/usbcoreblog/2010/02/05/how-to-generate-and-view-a-winusb-debug-trace-log/;带有USBPcap插件的Wireshark https://www.wireshark.org

其他例子:http://searchingforbit.blogspot.com/2012/04/winusb-communication-with-stm32-part-1.html。示例模板随Visual一起提供。

您还需要掌握编写.inf文件的知识。

另一种与USB - libusb-win32 32 https://sourceforge.net/projects/libusb-win32/通信的简单方法

我的简单示例控制台应用程序向设备发送小块数据(以保持活力):

代码语言:javascript
运行
复制
#include "stdafx.h"
#include <SetupAPI.h>
#include <Hidsdi.h> 
#include <devguid.h> 
#include <winusb.h>
#include <usb.h>
#pragma comment(lib, "hid.lib")
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "winusb.lib")
#include <iUString.h> 


iString<char> DevicePath;
bool                    WinusbHandle_Open=false;
bool                    DeviceHandle_Open = false;
WINUSB_INTERFACE_HANDLE WinusbHandle;
HANDLE                  DeviceHandle;
UCHAR usb_out_buffer[64];
DEFINE_GUID(GUID_DEVCLASS_WINUSB, 0x88bae032L, 0x5a81, 0x49f0, 0xbc, 0x3d, 0xa4, 0xff, 0x13, 0x82, 0x16, 0xd6);
DEFINE_GUID(GUID_DEVCLASS_STL, 0xf177724dL, 0x74d3, 0x430e, 0x86, 0xb5, 0xf0, 0x36, 0x89, 0x10, 0xeb, 0x23);
GUID winusb_guid;
GUID stl_guid;

bool connectusb();
void  disconnectusb();




int main()
{
    DWORD n;
    DWORD   numEvents;
    HANDLE rHnd;    

WinusbHandle_Open = false;
DeviceHandle_Open = false;
winusb_guid = GUID_DEVCLASS_WINUSB;
stl_guid = GUID_DEVCLASS_STL;
usb_out_buffer[0] = 0;
usb_out_buffer[1] = 1;
usb_out_buffer[2] = 2;
usb_out_buffer[3] = 3;

ULONG bytesWritten;
ULONG timeout;
timeout = 100;
rHnd = GetStdHandle(STD_INPUT_HANDLE);

WinUsb_SetPipePolicy(WinusbHandle, 0x01, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout);

timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, AUTO_CLEAR_STALL, sizeof(ULONG), &timeout);


timeout = TRUE;
WinUsb_SetPipePolicy(WinusbHandle, 0x01, RAW_IO, sizeof(ULONG), &timeout);//Bypasses queuing and error handling to boost performance for multiple read requests.


while (true)
{
if ((!WinusbHandle_Open) || (!WinusbHandle_Open)) { if (!connectusb())Sleep(2000); }
if ((!WinusbHandle_Open) || (!WinusbHandle_Open))continue;

bytesWritten = 0;
if (!WinUsb_WritePipe(WinusbHandle, 0x01, &usb_out_buffer[0], 2, &bytesWritten, NULL))
{
    n = GetLastError();
disconnectusb();
}
Sleep(2000);
}
disconnectusb();
return 0;
}




bool connectusb()
{
    BOOL                             bResult = FALSE;
    HDEVINFO                         deviceInfo;
    SP_DEVICE_INTERFACE_DATA         interfaceData;
    PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL;
    DWORD n;
    SP_DEVINFO_DATA devinfo;
    BYTE devdetailbuffer[4096];
    bool found;

    deviceInfo = SetupDiGetClassDevs(&stl_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (deviceInfo == INVALID_HANDLE_VALUE) { return false; }

    found = false;
    for (n = 0;; n++)
    {

        interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

        if (!SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &stl_guid, n, &interfaceData))
        {
            n = GetLastError();
            break;
        }




        detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)devdetailbuffer;
        detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
        devinfo.cbSize = sizeof(devinfo);
        if (!SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, detailData, sizeof(devdetailbuffer), NULL, &devinfo)) { printf("SetupDiGetDeviceInterfaceDetail: %u\n", GetLastError()); break; }
        if (IsEqualGUID(devinfo.ClassGuid, winusb_guid))
        {
            if ((-1 != iStrPos(detailData->DevicePath, "VID_0483")) || (-1 != iStrPos(detailData->DevicePath, "vid_0483")))
            {
                if ((-1 != iStrPos(detailData->DevicePath, "PID_576B")) || (-1 != iStrPos(detailData->DevicePath, "pid_576b")))
                {

                    DevicePath = detailData->DevicePath;
                    found = true;
                    break;
                }
            }
        }
    }



SetupDiDestroyDeviceInfoList(deviceInfo);
if (!found)return false;


DeviceHandle = CreateFile(DevicePath.Buffer() ,
    GENERIC_WRITE | GENERIC_READ,
    FILE_SHARE_WRITE | FILE_SHARE_READ,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
    NULL);

if (INVALID_HANDLE_VALUE == DeviceHandle) {
    n = GetLastError();
}

if (INVALID_HANDLE_VALUE == DeviceHandle) return false;
DeviceHandle_Open = true;



if (!WinUsb_Initialize(DeviceHandle, &WinusbHandle))
 {
     n = GetLastError();
     CloseHandle(DeviceHandle); DeviceHandle_Open = false;
     return false;
 }



WinusbHandle_Open = true;
return true;
}

void  disconnectusb()
{
    if (WinusbHandle_Open) { WinUsb_Free(WinusbHandle); WinusbHandle_Open = false; }
    if (DeviceHandle_Open) { CloseHandle(DeviceHandle); DeviceHandle_Open = false; }
}
票数 9
EN

Stack Overflow用户

发布于 2018-05-24 13:45:16

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38906880

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档