上位机与USB设备通信

   首先使用CreateFile打开USB端口,CreateFile函数会返回一个HANDLE类型的句柄,该句柄可以用于下述的ReadFile和WriteFile之间的操作。   

 

///  实现以指定的参数方式打开USB设备
CreateFile(devicePathName, 
		GENERIC_READ | GENERIC_WRITE,   // 已读写方式打开
		FILE_SHARE_READ| FILE_SHARE_WRITE, 
		0, 
		OPEN_EXISTING // 打开已经存在的设备,当设备不存在时会返回错误
		FILE_ATTRIBUTE_NORMAL| FILE_FLAG_OVERLAPPED,    // 通信时的一些属性的设置、FILE_FLAG_OVERLAPPED表示已异步的方式打开设备
);

 

 

 

 

 

这是最关键的一步是如何获取devicePathName, 幸好windows提供了解决的方法,

使用SetupDiGetClassDevs方法, 关于该方法在MSDN有非常详细的解答:

详细请参考以下网址:

 

 

// 关于HDEVINFO类型在setupapi.h文件中有定义
// typedef LPVOID HDEVINFO 
// 表示是一个指向void类型的指针
// 如果调用成功,返回所有符合要求的设备信息的句柄
// 如果调用失败,返回INVALID_HANDLE_VALUE
HDEVINFO  SetupDiGetClassDevs(
	_In_opt_ constGUID   *ClassGuid,   // 指向device setup class或device interface class接口的guid,这个参数是可选的,                                  // 可以为NULL
	_In_opt_       PCTSTREnumerator,   // 指向一个一NULL结尾的字符串,可以是即插即用设备的枚举器ID。该参数也是可选的,                                                 // 可以为NULL
	_In_opt_       HWND  hwndParent,
	_In_           DWORD Flags
);

// 调用方法  
 deviceInfoSet = SetupDiGetClassDevs( * guid,  NUL, NULL,  DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(deviceInfoSet == INVALID_HANDLE_VALUE)   // 失败
{}
else   // 成功
{}



如果想要获取详细的错误信息,通过调用GetLastError可以获取。
同时如果想要调用远程计算机上的设备的时候请使用SetupDiGetClassDevsEx。
当调用SetupDiGetClassDevs成功后,调用SetupDiEnumDeviceInterface方法,
枚举包含在设备信息集中的设备接口(enum the device information contained in the device
详细请参考下述网址:
https://msdn.microsoft.com/en-us/library/windows/hardware/ff551015(v=vs.85).aspx

 

 

一般的调用流程如下所述

SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

// 调用一次返回指定设备的硬件信息
while(SetupDiEnumDeviceInterface(deviceInfoSet,       // 设备信息集
			NULL, 
			*guid,      			//设备接口的guid,与SetupDiGetClassDevs保持一致即可
			deviceIndex,      		// 索引号,每调用一次该方法,加1,初始为0
			&deviceIntefaceData		//  SP_DEVICE_INTERFACE_DATA指针,记住在调用该方法之前必须设置cbSize的大小
		))
{
	DWORD bufferSize; 
	DWORD requiredSize; 
	SetupDiGetDeviceInterfaceDetail(deviceInfoSet,   // 
				&deviceInterfaceData, // 表示SP_DEVICE_INTERFACE_DATA,指定DeviceInfoSet的接口,一般来说是SetupDiEnumDeviceInterface返回// 的内容
				NULL, // SP_DEVICE_INTERFACE_DETAIL_DATA指针用来接收指定interface的信息
				0, // SP_DEVICE_INTERFACE_DETAIL_DATA的buffer大小,当上一个参数为NULL时,该参数必须为0
				&requiredSize, // 返回DeviceInterfaceDetailData的buffer 大小
				NULL );
}

 

 

 

 

 

 

// 第一次调用SetupDiGetDeviceInterfaceDetail方法后返回SP_DEVICE_INTERFACE_DETAIL_DATA的buffer大小

SP_DEVICE_INTERFACE_DETAIL_DATA detailBufferData;

detailBufferData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); // 如果指定了这个参数,那么在使用之前必须设置cbSize参数的大小

SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
 &deviceInterfaceData,   //
 &detailBufferData,     // SP_DEVICE_INTERFACE_DETAIL_DATA指针用来接收指定interface的信息
 requiredSize,         // 上一次调用后返回的SP_DEVICE_INTERFACE_DETAIL_DATA的buffer大小
 &requiredSize,         // 返回DeviceInterfaceDetailData的buffer 大小
 NULL );

//  如果SetupDiDeviceInterfaceDetail调用成功,detailBufferData包含有USB设备的路径信息。

}

 

 

关于SetupDiGetInterfaceDetail方法的详细请参考下述网址

 

 

还有一个非常重要的结构体需要介绍下。

SP_DEVICE_INTERFACE_DETAIL_DATA

关于详细的资料可以参考以下网址:

 

 

 
// 该结构体返回的DevicePath即设备的路径
typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
  DWORD cbSize;      // 表示该结构体的大小
  TCHAR DevicePath[ANYSIZE_ARRAY];    // 已NULL结尾,包括设备接口路径的字符串(device interface path)
				      // 这个路径信息可以传递给一些win32函数,例如 CreateFile:
} SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA;

 

 

备注: 在SetupDiXXX系列函数中,当SP_DEVICE_INTERFACE_DETAIL_DATA以参数的形式传递时,

函数会判断结构体的大小与成员cbSize是否一致,否则调用的函数会返回error。

 

 

 

 

 

 

 

/*

调用SetupDiGetClassDevs方法后,请调用SetupDiEnumDeviceInfo方法。该方法返回的SP_DEVINFO_DATA结构体指定了device information set集合中的设备元素信息。

*/

 

然后是读写USB设备,这有好几种方法,这里介绍两种:

①:ReadFile和WriteFile;

②:使用winusb_readpipe和winusb_writepipe方法;

 

 

 

最后当不再需要的时候一定要记得删除SetupDiGetClassDevs的返回信息,通过调用SetupDiDestroyDeviceInfoList函数即可,关于该函数的详细的介绍请参考下述MSDN网址

 

 

 

 因为晚上时间有限,写的有不正确的地方希望大家指出来。

 

参考:

http://blog.csdn.net/tody_guo/article/details/8675237

 

你可能感兴趣的:(USB通信)