以前看 USB 协议 2.0 的时候,有个认识上的误区,认为所谓的复合设备,必须是两个物理上相独立的 USB 设备(两个 USB Device ,两个 USB 地址,只是在同一条 USB 总线而已)。最近在开发 .Net Micro Framewok 的 USB 双接口功能时,才明白复合设备原来也可以是这样实现 !
对 USB 设备来说,至少会有一个 USB 配置,而这个配置可以包括一到多个接口,而一个接口又可以包括多个端点。对 Windows 平台来说,每一个接口在逻辑上对应一个虚拟设备,可以分别安装不同的驱动(视接口的配置来定,即使两个接口配置一样,也需要安装两次相同的驱动),但从表面上看和两个真实的物理 USB 设备没有什么不同。
1 为什么要实现双接口
有在 .Net Micro Framework 调试 SideShow 经验的用户,就会有特别深的感触,因为 SideShow 通信是基于 USB ,而大部分 .Net Micro Framework 调试口也是基于 USB ,由于只有一个接口,所以 PC 端要么安装 SideShow 驱动,要么安装 .Net Micro Frame USB 设备驱动,二者不能共存(当然让两个驱动共存,也可以设置不同的 PID 和 VID ,但是这样就需要在 .Net Micro Frame 开发板上进行相应的配置了),别说在线调试了,光编译下载,就不知道要折腾好几回。
所以对只有一个 USB Debug 口的开发板,要调试 USB 相关例程是非常痛苦的。
而 USB 双接口的方案就是为解决该问题而生。同时有两个 USB 接口,即可以安装两个不同的驱动,也可以在线调试 USB 例程。这是多么一个令人神往的特性,尤为可喜的是这已经不仅仅是个意境,现如今已成为现实。目前我们已经测试通过的有: Debug+Mass Storage ( U 盘), Debug+HID (鼠标), Debug+Application (应用口)。当然也可以根据需要配置成三个、四个设置或多个你任意想要的接口。
2 支持双接口,需要做些什么
.Net Micro Framework USB 接口模型
第一、 修改 .Net Micro Framework 的 USB 接口配置,把一个接口修改成两个接口;
第二、 修改 .Net Micro Framework 的 USB 接口驱动,以前仅支持端点 1 和端点 2 ,目前增加对端点 3 和端点 4 的支持。逻辑上接口 1 包括端点 1 和端点 2 ,接口 2 包括端点 3 和端点 4 ;
第三、 修改 PAL 层接口,增加端点 3 和端点 4 的读写接口函数;
第四、 编写 P/Invoke 接口,让 C# 程序也可以读写端点 3 和端点 4 的数据(端点 1 和端点 2 默认供调试程序读写用);
第五、 修改 .Net Micro Frame USB Windows 驱动,让其支持双接口。(当然如果你的接口配置为 HID 或 Mass Storage ,那就不需要开发专门的驱动了);
第六、 剩下的就是测试再测试了。
3 一个双接口通信的例子
驱动程序等等安装完毕,准备停当之后,我们需要编写两部分程序来调试 USB 应用。一是普通 Windows USB 读写程序,这个程序我在以前写的 Blog 上已经介绍了( http://blog.csdn.net/yefanqiu/archive/2009/01/21/3849067.aspx )这里就不多说了;二是开发一个 .Net Micro Frame USB Device 应用程序,来响应 Windows 平台的 USB 读写程序。
我们的程序很简单,实现一个转发功能,也就是把 Windows 平台的 USB 程序发送的数据,原封不动的发送回去。代码如下:
using System;
using Microsoft.SPOT;
using System.Threading;
using Microsoft.SPOT.Hardware;
namespace USBDeviceTest
{
public class Program
{
public static void Main()
{
byte [] bytData= new byte [1024];
YFInterop. MFNative .Usb_Open(0);
while ( true )
{
int intSize=YFInterop. MFNative .Usb_Available();
if (intSize > 0)
{
if (YFInterop. MFNative .Usb_Read(bytData, 0, intSize) == intSize)
{
string strData = intSize.ToString()+ ":" ;
for ( int i = 0; i < intSize; i++)
{
strData += bytData[i].ToString() + " " ;
}
Debug .Print(strData);
YFInterop. MFNative .Usb_Write(bytData, 0, intSize);
}
}
Thread .Sleep(3);
}
YFInterop. MFNative .Usb_Close();
}
}
}
注:测试时, VS2008 可以一直处在调试模式(可即时打印调试信息),此时 USB Test 程序同时完成数据收发。