教程:实现WinUSB通信系统的最简单的方式

2019-01-11 09:34:28 来源:ofweek
标签:

 

前言

USB接口作为PC上最流行和通用的接口,具备可连接多种类型的设备,连接简单,即插即用,支持热插拨,多数应用场景下不需要提供独立的电源,高传输速率,高可靠性等特点,被越来越多的产品作为首选接口作为接入PC的连接方式。为了简化USB设备的开发和接入到PC系统,微软开发了WinUSB,可以将Winusb.sys作为设备功能驱动程序安装,并提供WinUSB API供应用程序访问设备。一直以来,除了USB HID设备,其他类型的设备在WINDOWS环境下需要安装驱动程序才能工作。要实现USB设备免驱,就只能使用HID设备。而HID设备传输速度慢,在有些场合必须使用Bulk类型进行批量传输时,就必须使用第三方驱动或者自己开发一个驱动,使得项目开发非常麻烦。现在好了,自从微软推出了WinUSB,在微软的最新操作系统上实现简单的Bulk类型批量传输也变得非常的方便快捷,在研发过程当中或者一些对于差异化要求不高的场合,是非常适用且容易实现的。本文致力于实现一个最简单的WinUSB通信系统,以满足此类需求。

 

如何让嵌入式设备枚举成WinUSB设备

系统通过USB描述符来确定以何种USB Class类型来工作。如果希望WINDOWS能够将嵌入式设备识别为WinUSB设备,则其描述符至少应当包含以下字段:

 

1、支持 OS 字符串描述符:

为了让 USB 驱动程序堆栈了解设备支持扩展的特征描述符,设备必须定义存储在字符串索引 0xEE 处的 OS 字符串描述符。在枚举过程中,驱动程序堆栈查询字符串描述符。如果存在描述符,驱动程序堆栈会假定设备包含一个或多个 OS 特征描述符和检索这些特征描述符所需要的数据。检索的字符串描述符具有 bMS_VendorCode 字段值。该值为1表示USB驱动程序堆栈必须用来检索扩展特征描述符的供应商代码。

 

#define bMS_VendorCode              ( 0x01 )

// "MSFT100" : index : 0xEE : langId : 0x0000

const U8 OS_StringDescritpor[ ] =

{ 0x12,  0x03,  'M',  0,  'S',  0,  'F',  0,  'T',  0,  '1',  0,  '0',  0,  '0',  0,  bMS_VendorCode,  0 };

 

2、设置兼容ID特征描述符:

const U8 WINUSB_ExtendedCompatId_Descritpor[ ] =

0x28, 0x00, 0x00, 0x00,           // dwLength

0x00, 0x01,                             // bcdVersion

0x04, 0x00,                             // wIndex

0x01,                                       // bCount

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,       // Reserved[7]

0x00,                   // bFirstInterfaceNumber

0x01,                  // RESERVED ( 0x01 )

'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,       // compactiableID[8]

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompactiableID[8]

0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // Reserved[6]

};

注:WinUSB还支持复合设备,对于单一传输类型最简系统,我们忽略复合设备的要求即可。compatibleID字段必须指定 "WINUSB" 作为字段值。其他可以根据需求更改。

 

3、注册设备接口 GUID描述符:

该描述符用于区分不同的WinUSB设备。

 

const U8 WINUSB_ExtendedProperty_InterfaceGUID_Descritpor[ ] =

0x8E, 0x00, 0x00, 0x00,  // dwTotalSize = Header + All sections

0x00, 0x01,                 // bcdVersion

0x05, 0x00,                 // wIndex

0x01, 0x00,                 // wCount

0x84, 0x00, 0x00, 0x00,     // dwSize -- this section

0x01, 0x00, 0x00, 0x00,     // dwPropertyDataType

0x28, 0x00,               // wPropertyNameLength  'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,'I',0,'n',0x00,'t',0,'e',0,'r',0,'f',0,'a',0,'c',0,'e',0, 'G',0,'U',0,'I',0,'D',0,0,0,

0x4E, 0x00, 0x00, 0x00,     // dwPropertyDataLength : 78 Bytes = 0x0000004E

'{',0,'1',0,'2',0,'3',0,'4',0, '5',0,'6',0,'7',0,'8',0,'-',0,'1',0,'2',0,'3',0,'4',0,'-',0,'1',0,'3',0,'4',0,'4',0,'-',0,'1',0,'2',0,'3',0,'4',0,'-',0,'1',0,'2',0,'3',0,'4',0,'5',0,'6',0,'7',0,'8',0,'9',0,'A',0,'B',0,'C',0,'}',0,0,0

};// bPropertyData : WCHAR : L"{12345678-1234-1234-1234-123456789ABC}"

 

4、端点描述符:

按实际的需求的配置端点数量和类型,即可完成嵌入式设备的描述符配置了。

 

一般固件程序可以通过MCU厂家提供的范例程序进行修改,这里省略USB固件功能的说明。只要包含以上三个描述符中的必须的字段,就可以成功枚举成USB Device。枚举成功后在设备WINDOWS设备管理器中可看到类似设备,如下图1所示

 

图1 成功枚举为USB Device

 

如何编写PC应用程序与嵌入式设备进行USB通信

PC机软件相对来说比较简单,并且微软官方也给出了示例代码。唯一需要注意的是,对应的软件程序获取WinUSB设备句柄的GUID参数,需要与嵌入式设备的描述符中的GUID保持一致。GUID是WinUSB用以区分设备的唯一标志。GUID,是Globally Unique Identifier的简称,翻译为全局唯一标识符,是一种由算法生成的二进制数据,长度为128位的数字标识符。

 

具体实现步骤如下:

1、创建设备的文件句柄:

调用SetupDiGetClassDevs 获取设备信息集的句柄;

调用 SetupDiEnumDeviceInterfaces 枚举设备信息集中的设备接口并获取有关设备接口的信息;

调用 SetupDiGetDeviceInterfaceDetail 获取设备接口的详细信息,所获取的信息通过SP_DEVICE_INTERFACE_DETAIL_DATA结构返回。由于该结构大小无法提前获取,故需连续两次调用该函数,第二次调用时接口详细信息将填充到根据第一次调用返回值所确定大小的该缓冲区,通过缓冲内该结构的DevicePath成员中可获得“设备路径”。

 

2、获取设备的 WinUSB 接口句柄:

调用 WinUsb_Initialize通过传递在创建设备的文件句柄中创建的文件句柄。

 

3、查询设备以获取 USB 描述符:

接下来,查询设备以获取特定于 USB 的信息,如设备速度、接口描述符、相关端点及其管道。调用 WinUsb_QueryDeviceInformation 从设备的设备描述符请求信息。调用 WinUsb_QueryInterfaceSettings 并传递设备的接口句柄,以获得对应的接口描述符。调用 WinUsb_QueryPipe 获取有关每个接口每个终结点的信息。此步骤不是必须的,因为端点方向及传输特性由嵌入式设备描述符决定,是已知的。

 

4、向默认端点发送控制传输:

此步骤也不是必须的。一般都不通过默认端点发送有效载荷。

 

5、发送 I/O 请求:

将数据发送到设备的批量输入和批量输出端点,这些端点点可分别用于读取请求和写入请求。调用 WinUsb_ReadPipe 从设备的批量输入端点读取数据。调用 WinUsb_WritePipe 通过批量输出端点将数据写入设备。在嵌入式设备的输出端点内写入数据之后,就可以在PC端读出数据。反之,如果在PC端对嵌入式设备的输入端点写入数据,则嵌入式设备会产生一个USB端点写入事件,具体如何捕捉该事件,则由MCU厂家的产品硬件决定,产生相应的中断信息,供中断服务程序来判断。一般而言,芯片厂家会提供MCU的USB通信基础范例程序,在其基础上做简单的修改和适配即可。

 

6、释放设备句柄

在完成对设备的所有必要的调用之后,释放设备的文件句柄和 WinUSB 接口句柄。CloseHandle 释放由 CreateFile 创建的句柄。

WinUsb_Free 释放由 WinUsb_Initialize 返回的设备的 WinUSB 接口句柄。

至此,已经完成了嵌入式设备端固件的USB代码移植和PC端应用程序的编写,就可以实现USB免驱设备的通信方式了。

 
关注与非网微信 ( ee-focus )
限量版产业观察、行业动态、技术大餐每日推荐
享受快时代的精品慢阅读
 

 

继续阅读
微软凭借云服务强劲增长,市值能否破万亿美元?

而积极向云和物联网转型的企业则迎来重大机遇,微软就是尤为典型的例子此前微软首席执行官萨提亚·纳德拉在接受财新周刊》专访谈及到把握计算的走向至关重要,计算正被嵌入世界每一个角落和每一台设备,所有行业都在被数字化技术所改变。

Patton凭借微软Skype for Business认证实现云端整合

提供统一通信 (UC)、统一通信即服务 (UCaaS) 和云端技术支持的美国解决方案提供商Patton现在宣布所有SmartNode VoIP(网络电话)产品3.X版(包括 Virtual SmartNode (vSN))均已通过 Skype for Business (SfB) 的互操作性认证。

比尔盖茨:人工智能应被用于医疗和教育领域

根据《CNET》报导,微软创办人比尔盖茨认为,人工智能(AI)是一把双面刃,为了确保能够好好利用这项技术,应该要将其用于医疗或教育相关的领域。

微软开源数据计划是在下怎样的一盘棋?

微软新推出的Project Zipline压缩算法,足够快到可以在压缩数据的同时,把数据写入SSD或者从物联网设备进行上传,而且在微软内部工作负载,也就是最初开发时的目标对象上获得高达96%的压缩率。

HoloLens 2搭载的黑科技一览,眼球追踪技术成最大亮点
HoloLens 2搭载的黑科技一览,眼球追踪技术成最大亮点

HoloLens 2现在可以接受预订,并将于今年晚些时候开始发货,虽然微软并没有透露它的重量,但是多位体验者都认为比上个版本要轻,而且更加舒服,也比较容易控制。

更多资讯
从UI/操作/动画/游戏优化等细节全面了解OPPO的ColorOS 6
从UI/操作/动画/游戏优化等细节全面了解OPPO的ColorOS 6

去年已经亮相过的ColorOS 6正式登场亮相。我们已经了解到,ColorOS 6对UI界面、字体、功能做出了相当大的改变,OPPO的R15等手机也已经在公测中率先或了新系统的升级。

更简单的扩展,工程师教你做I2C编码器
更简单的扩展,工程师教你做I2C编码器

用于连接I2C总线上的多个旋转编码器。支持RGB编码器,扩展到7bit的寻址。

自主研发一个操作系统究竟有多难?华为的麒麟OS什么时候可以上线?
自主研发一个操作系统究竟有多难?华为的麒麟OS什么时候可以上线?

近日华为消费者CEO余承东在接受采访的时候表示自主操作系统已准备好,但是目前形势下还是优先与微软Windows和谷歌的Android进行合作,显示出在推行自主操作系统方面依然颇为犹豫,这是基于现实做出的选择。

风河再次名列全球领先嵌入式操作系统提供商

领先的关键基础设施物联网软件提供商风河公司近日发布了令人振奋的成就,根据VDC Research的研究报告,风河公司继续保持着嵌入式实时操作系统(RTOS)及商用Linux市场营收领先者的地位。同时,风河公司还被评为商用级嵌入式Hypervisors和安全操作系统的领先提供商。

搭载商用BGA处理器的 高品质嵌入式板

提供标准和定制化嵌入式计算机主板与模块的领导厂商-德国康佳特科技,在2019纽伦堡嵌入式展中首先全球推出基于全新第八 英特尔® 酷睿™ 移动式处理器 (代号名: Whiskey Lake)的嵌入式板卡与模块,包含COM Express Type6 Compact 计算机模块,3.5”单板和Thin Mini-ITX主板。

电路方案