// Include Windows headers
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
// Include WinUSB headers
#include <winusb.h>
#include <Usb100.h>
#include <Setupapi.h>
// Linked libraries
#pragma comment (lib , "setupapi.lib" )
#pragma comment (lib , "winusb.lib" )
//为在 INF 文件中提供的用于安装 Winusb.sys 的设备接口标识符声明一个常量。
// Constant for {D696BFEB-1734-417d-8A04-86D01071C512}
//static const GUID OSR_DEVICE_INTERFACE =
//{ 0xd696bfeb, 0x1734, 0x417d, { 0x8a, 0x04, 0x86, 0xd0, 0x10, 0x71, 0xc5, 0x12 } };
//ClassGuid= {78A1C341-4539-11d3-B88D-00C04FAD5171}
//DeviceInterfaceGUIDs,0x10000,"{b35924d6-3e16-4a9e-9782-5524a4b79bac}"
static const GUID OSR_DEVICE_INTERFACE =
{ 0xb35924d6, 0x3e16, 0x4a9e, { 0x97, 0x82, 0x55, 0x24, 0xa4, 0xb7, 0x9b, 0xac } };
BOOL GetDeviceHandle (GUID guidDeviceInterface, PHANDLE hDeviceHandle)
{
if (guidDeviceInterface==GUID_NULL)
{
return FALSE;
}
BOOL bResult = TRUE;
HDEVINFO hDeviceInfo;
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = NULL;
ULONG requiredLength=0;
LPTSTR lpDevicePath = NULL;
DWORD index = 0;
BOOL SetupRet=FALSE;
// Get information about all the installed devices for the specified
// device interface class.
hDeviceInfo = SetupDiGetClassDevs(
&guidDeviceInterface,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDeviceInfo == INVALID_HANDLE_VALUE)
{
// ERROR
printf("Error SetupDiGetClassDevs: %d.\n", GetLastError());
goto done;
}
//Enumerate all the device interfaces in the device information set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
index = 0;
SetupRet=SetupDiEnumDeviceInfo(hDeviceInfo, index, &DeviceInfoData);
for (; SetupRet!=FALSE ; SetupRet=SetupDiEnumDeviceInfo(hDeviceInfo, ++index, &DeviceInfoData))
{
//Reset for this iteration
if (lpDevicePath)
{
LocalFree(lpDevicePath);
}
if (pInterfaceDetailData)
{
LocalFree(pInterfaceDetailData);
}
deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
//Get information about the device interface.
bResult = SetupDiEnumDeviceInterfaces(
hDeviceInfo,
&DeviceInfoData,
&guidDeviceInterface,
0,
&deviceInterfaceData);
// Check if last item
if (GetLastError () == ERROR_NO_MORE_ITEMS)
{
break;
}
//Check for some other error
if (!bResult)
{
printf("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError());
goto done;
}
//Interface data is returned in SP_DEVICE_INTERFACE_DETAIL_DATA
//which we need to allocate, so we have to call this function twice.
//First to get the size so that we know how much to allocate
//Second, the actual call with the allocated buffer
bResult = SetupDiGetDeviceInterfaceDetail(
hDeviceInfo,
&deviceInterfaceData,
NULL, 0,
&requiredLength,
NULL);
//Check for some other error
if (!bResult)
{
if ((ERROR_INSUFFICIENT_BUFFER==GetLastError()) && (requiredLength>0))
{
//we got the size, allocate buffer
pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, requiredLength);
if (!pInterfaceDetailData)
{
// ERROR
printf("Error allocating memory for the device detail buffer.\n");
goto done;
}
}
else
{
printf("Error SetupDiEnumDeviceInterfaces: %d.\n", GetLastError());
goto done;
}
}
//get the interface detailed data
pInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//Now call it with the correct size and allocated buffer
bResult = SetupDiGetDeviceInterfaceDetail(
hDeviceInfo,
&deviceInterfaceData,
pInterfaceDetailData,
requiredLength,
NULL,
&DeviceInfoData);
//Check for some other error
if (!bResult)
{
printf("Error SetupDiGetDeviceInterfaceDetail: %d.\n", GetLastError());
goto done;
}
//copy device path
size_t nLength = wcslen (pInterfaceDetailData->DevicePath) + 1;
lpDevicePath = (TCHAR *) LocalAlloc (LPTR, nLength * sizeof(TCHAR));
StringCchCopy(lpDevicePath, nLength, pInterfaceDetailData->DevicePath);
lpDevicePath[nLength-1] = 0;
printf("Device path: %s\n", lpDevicePath);
}
if (!lpDevicePath)
{
//Error.
printf("Error %d.", GetLastError());
goto done;
}
//Open the device
*hDeviceHandle = CreateFile (
lpDevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (*hDeviceHandle == INVALID_HANDLE_VALUE)
{
//Error.
printf("Error %d.", GetLastError());
goto done;
}
done:
LocalFree(lpDevicePath);
LocalFree(pInterfaceDetailData);
bResult = SetupDiDestroyDeviceInfoList(hDeviceInfo);
return bResult;
}
BOOL GetWinUSBHandle(HANDLE hDeviceHandle, PWINUSB_INTERFACE_HANDLE phWinUSBHandle)
{
if (hDeviceHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bResult = WinUsb_Initialize(hDeviceHandle, phWinUSBHandle);
if(!bResult)
{
//Error.
printf("WinUsb_Initialize Error %d.", GetLastError());
return FALSE;
}
return bResult;
}
//以下示例代码获取由 WinUSB 接口句柄指定的设备的速度。
BOOL GetUSBDeviceSpeed(WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pDeviceSpeed)
{
if (!pDeviceSpeed || hDeviceHandle==INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bResult = TRUE;
ULONG length = sizeof(UCHAR);
bResult = WinUsb_QueryDeviceInformation(hDeviceHandle, DEVICE_SPEED, &length, pDeviceSpeed);
if(!bResult)
{
printf("Error getting device speed: %d.\n", GetLastError());
goto done;
}
if(*pDeviceSpeed == LowSpeed)
{
printf("Device speed: %d (Low speed).\n", *pDeviceSpeed);
goto done;
}
if(*pDeviceSpeed == FullSpeed)
{
printf("Device speed: %d (Full speed).\n", *pDeviceSpeed);
goto done;
}
if(*pDeviceSpeed == HighSpeed)
{
printf("Device speed: %d (High speed).\n", *pDeviceSpeed);
goto done;
}
done:
return bResult;
}
//以下示例代码查询由 WinUSB 接口句柄指定的 USB 设备的各种描述符。
//此示例函数检索支持的终结点类型及其管道标识符。
//该示例存储所有三个 PipeId 值以供日后使用。
struct PIPE_ID
{
UCHAR PipeInId;
UCHAR PipeOutId;
};
BOOL QueryDeviceEndpoints (WINUSB_INTERFACE_HANDLE hDeviceHandle, PIPE_ID* pipeid)
{
if (hDeviceHandle==INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bResult = TRUE;
USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
ZeroMemory(&InterfaceDescriptor, sizeof(USB_INTERFACE_DESCRIPTOR));
WINUSB_PIPE_INFORMATION Pipe;
ZeroMemory(&Pipe, sizeof(WINUSB_PIPE_INFORMATION));
bResult = WinUsb_QueryInterfaceSettings(hDeviceHandle, 0, &InterfaceDescriptor);
if (bResult)
{
for (int index = 0; index < InterfaceDescriptor.bNumEndpoints; index++)
{
bResult = WinUsb_QueryPipe(hDeviceHandle, 0, index, &Pipe);
if (bResult)
{
if (Pipe.PipeType == UsbdPipeTypeControl)
{
printf("Endpoint index: %d Pipe type: Control Pipe ID: %d.\n", index, Pipe.PipeType, Pipe.PipeId);
}
if (Pipe.PipeType == UsbdPipeTypeIsochronous)
{
printf("Endpoint index: %d Pipe type: Isochronous Pipe ID: %d.\n", index, Pipe.PipeType, Pipe.PipeId);
}
if (Pipe.PipeType == UsbdPipeTypeBulk)
{
if (USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId))
{
printf("Endpoint index: %d Pipe type: Bulk Pipe ID: %c.\n", index, Pipe.PipeType, Pipe.PipeId);
pipeid->PipeInId = Pipe.PipeId;
}
if (USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId))
{
printf("Endpoint index: %d Pipe type: Bulk Pipe ID: %c.\n", index, Pipe.PipeType, Pipe.PipeId);
pipeid->PipeOutId = Pipe.PipeId;
}
}
if (Pipe.PipeType == UsbdPipeTypeInterrupt)
{
printf("Endpoint index: %d Pipe type: Interrupt Pipe ID: %d.\n", index, Pipe.PipeType, Pipe.PipeId);
}
}
else
{
continue;
}
}
}
done:
return bResult;
}
//向默认终结点发送控制传输
//接下来,通过向默认终结点发送控制请求来与设备通信。
//除了与接口关联的终结点之外,所有 USB 设备都有一个默认终结点。
//默认终结点的主要目的是为主机提供可用于配置设备的信息。
//不过,设备还可以将默认终结点用于特定于设备的目的。
//例如,OSR USB FX2 设备使用默认终结点控制灯条和七段数字显示。
//-------------------------------------------------------
//使用以下步骤发送控制请求。
//1. 分配一个 1 字节的数据缓冲区,并将数据加载到缓冲区,该缓冲区通过设置适当的位指定应亮起的元素。
//2. 在调用方分配的 WINUSB_SETUP_PACKET 结构中构建一个安装包。如下所示初始化成员以表示请求类型和数据:
//RequestType 成员指定请求方向。它设置为 0,指示主机到设备数据传输。对于设备到主机传输,将 RequestType 设置为 1。
//Request 成员设置为此请求的供应商定义的代码 0xD8。为简便起见将其定义为 SET_BARGRAPH_DISPLAY。
//Length 成员设置为数据缓冲区的大小。
//此请求不需要 Index 和 Value 成员,因此它们设置为零。
//3. 调用 WinUsb_ControlTransfer 以通过传递设备的 WinUSB 接口句柄、安装包和数据缓冲区,将请求传输到默认终结点。
//此函数在 LengthTransferred 参数中接收传输到设备的字节数。
//---------------------------------------------------------
//以下代码示例将控制请求发送到指定的 USB 设备来控制灯条上的灯。
BOOL SendDatatoDefaultEndpoint(WINUSB_INTERFACE_HANDLE hDeviceHandle)
{
if (hDeviceHandle==INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bResult = TRUE;
UCHAR bars = 0;
WINUSB_SETUP_PACKET SetupPacket;
ZeroMemory(&SetupPacket, sizeof(WINUSB_SETUP_PACKET));
ULONG cbSent = 0;
//Set bits to light alternate bars
for (short i = 0; i < 7; i+= 2)
{
bars += 1 << i;
}
//Create the setup packet
SetupPacket.RequestType = 0;
SetupPacket.Request = 0xD8;
SetupPacket.Value = 0;
SetupPacket.Index = 0;
SetupPacket.Length = sizeof(UCHAR);
bResult = WinUsb_ControlTransfer(hDeviceHandle, SetupPacket, &bars, sizeof(UCHAR), &cbSent, 0);
if(!bResult)
{
goto done;
}
printf("Data sent: %d \nActual data transferred: %d.\n", sizeof(bars), cbSent);
done:
return bResult;
}
//发送 I/O 请求
//接下来,将数据发送到设备的批量传入和批量传出终结点,这些终结点可分别用于读取请求和写入请求。
//在 OSR USB FX2 设备上,这两个终结点配置为用于环回,
//因此该设备可将数据从批量传入终结点移动到批量传出终结点。
//它不更改数据的值或添加任何新数据。对于环回配置,
//读取请求将读取由最近的写入请求发送的数据。
//WinUSB 提供以下函数用于发送读取请求和写入请求:
//" WinUsb_WritePipe
//" WinUsb_ReadPipe
//发送写入请求
//1. 分配一个缓冲区,并使用希望写入设备的数据填充该缓冲区。
//如果应用程序没有将 RAW_IO 设置为管道的策略类型,则对缓冲区大小没有限制。
//WinUSB 根据需要将缓冲区拆分为适当大小的区块。如果设置了 RAW_IO,
//则缓冲区的大小受 WinUSB 支持的最大缓冲区大小的限制。
//2. 调用 WinUsb_WritePipe 将缓冲区写入设备。传递设备的
// WinUSB 接口句柄、批量传出管道的管道标识符(如本主题的查询设备以获取 USB 描述符部分所述)
// 和缓冲区。此函数返回在 bytesWritten 参数中实际写入设备的字节数。
// Overlapped 参数设置为 NULL 以请求同步操作。要执行异步写请求,
// 请将Overlapped 设置为指向 OVERLAPPED 结构的指针。
//包含零长度数据的写入请求向下转发到 USB 堆栈。如果传输长度大于最大传输长度,
//WinUSB 会将请求拆分为具有最大传输长度的较小请求,并连续提交它们。
//以下代码示例分配一个字符串,并将其发送到设备的批量传出终结点。
BOOL WriteToBulkEndpoint(WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pID, ULONG* pcbWritten)
{
if (hDeviceHandle==INVALID_HANDLE_VALUE || !pID || !pcbWritten)
{
return FALSE;
}
BOOL bResult = TRUE;
//UCHAR szBuffer[] = "Hello World";
unsigned char sendData=2; //0,1,2,3
int a=-1;
while(a<0 || a>3)
{
printf("input a number between 0~3, (0:all on;1:D3 on;2:D4 on;3 all off)\n");
scanf("%d",&a);
getchar();
}
sendData=a;
//ULONG cbSize = strlen((char *)szBuffer);
ULONG cbSize = sizeof(sendData);
ULONG cbSent = 0;
//bResult = WinUsb_WritePipe(hDeviceHandle, *pID, szBuffer, cbSize, &cbSent, 0);
bResult = WinUsb_WritePipe(hDeviceHandle, *pID, &sendData, cbSize, &cbSent, 0);
if(!bResult)
{
goto done;
}
//printf("Wrote to pipe %d: %s \nActual data transferred: %d.\n", *pID, szBuffer, cbSent);
printf("Wrote to pipe %d: %d \nActual data transferred: %d.\n", *pID, sendData, cbSent);
*pcbWritten = cbSent;
done:
return bResult;
}
//发送读取请求
//" 调用 WinUsb_ReadPipe 从设备的批量传入终结点读取数据。
//传递设备的 WinUSB 接口句柄、批量传入终结点的管道标识符和适当大小的空缓冲区。
//当该函数返回时,缓冲区包含从设备读取的数据。读取的字节数返回函数的 bytesRead 参数。
//对于读取请求,缓冲区必须是最大包大小的倍数。
//零长度读请求将立即成功完成,并且不向下发送到堆栈。如果传输长度大于最大传输长度,
//WinUSB 会将请求拆分为具有最大传输长度的较小请求,并连续提交它们。
//如果传输长度不是终结点的 MaxPacketSize 的倍数,WinUSB 会将传输大小增加到 MaxPacketSize 的下一个倍数。
//如果设备返回的数据比请求的多,WinUSB 会保存超过的数据。如果数据从以前的读请求中保留,
//WinUSB 会将其复制到下一个读请求的开头,并根据需要完成请求。
//以下代码示例从设备的批量传入终结点读取数据。
//-----------------------------------------------------
BOOL ReadFromBulkEndpoint(WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pID, ULONG cbSize)
{
if (hDeviceHandle==INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bResult = TRUE;
UCHAR* szBuffer = (UCHAR*)LocalAlloc(LPTR, sizeof(UCHAR)*cbSize);
ULONG cbRead = 0;
bResult = WinUsb_ReadPipe(hDeviceHandle, *pID, szBuffer, cbSize, &cbRead, 0);
if(!bResult)
{
goto done;
}
printf("Read from pipe %d: %s \nActual data read: %d.\n", *pID, szBuffer, cbRead);
done:
LocalFree(szBuffer);
return bResult;
}
//释放设备句柄
//在完成对设备的所有必要的调用之后,释放设备的文件句柄和 WinUSB 接口句柄。 为此,调用以下函数:
//" CloseHandle 释放由 CreateFile 创建的句柄,如本演练的创建设备的文件句柄一节中所述。
//" WinUsb_Free 释放由 WinUsb_Initialize 返回的设备的 WinUSB 接口句柄。
enum ERR_TYPE{
NoErr,
GetDeviceHandleErr,
GetWinUSBHandleErr,
GetUSBDeviceSpeedErr,
QueryDeviceEndpointsErr,
SendDatatoDefaultEndpointErr,
WriteToBulkEndpointErr,
ReadFromBulkEndpointErr
};
void perr(ERR_TYPE errcode)
{
static char err_message[][30]={
"NoErr",
"GetDeviceHandleErr",
"GetWinUSBHandleErr",
"GetUSBDeviceSpeedErr",
"QueryDeviceEndpointsErr",
"SendDatatoDefaultEndpointErr",
"WriteToBulkEndpointErr",
"ReadFromBulkEndpointErr"
};
if (errcode==NoErr)
{
printf("no error occur!\n");
return;
}
printf("error message:%s\n",err_message[errcode]);
printf("GetLastError:%d\n",GetLastError());
}
//实现主函数
//以下代码示例显示了控制台应用程序的主函数。
int _tmain(int argc, _TCHAR* argv[])
{
ERR_TYPE errcode=NoErr;
GUID guidDeviceInterface = OSR_DEVICE_INTERFACE; //in the INF file
BOOL bResult = TRUE;
PIPE_ID PipeID;
HANDLE hDeviceHandle = INVALID_HANDLE_VALUE;
WINUSB_INTERFACE_HANDLE hWinUSBHandle = INVALID_HANDLE_VALUE;
UCHAR DeviceSpeed;
ULONG cbSize = 0;
bResult = GetDeviceHandle(guidDeviceInterface, &hDeviceHandle);
if(!bResult)
{
errcode=GetDeviceHandleErr;
goto maindone;
}
bResult = GetWinUSBHandle(hDeviceHandle, &hWinUSBHandle);
if(!bResult)
{
errcode=GetWinUSBHandleErr;
goto maindone;
}
bResult = GetUSBDeviceSpeed(hWinUSBHandle, &DeviceSpeed);
if(!bResult)
{
errcode=GetUSBDeviceSpeedErr;
goto maindone;
}
bResult = QueryDeviceEndpoints(hWinUSBHandle, &PipeID);
if(!bResult)
{
errcode=QueryDeviceEndpointsErr;
goto maindone;
}
#if 0
bResult = SendDatatoDefaultEndpoint(hWinUSBHandle);
if(!bResult)
{
errcode=SendDatatoDefaultEndpointErr;
goto maindone;
}
#endif
bResult = WriteToBulkEndpoint(hWinUSBHandle, &PipeID.PipeOutId, &cbSize);
if(!bResult)
{
errcode=WriteToBulkEndpointErr;
goto maindone;
}
bResult = ReadFromBulkEndpoint(hWinUSBHandle, &PipeID.PipeInId, cbSize);
if(!bResult)
{
errcode=ReadFromBulkEndpointErr;
goto maindone;
}
maindone:
CloseHandle(hDeviceHandle);
WinUsb_Free(hWinUSBHandle);
perr(errcode);
system("PAUSE");
return 0;
}
/*
Device path: \
Device speed: 1 (Low speed).
Endpoint index: 0 Pipe type: Bulk Pipe ID: ..
Endpoint index: 1 Pipe type: Bulk Pipe ID: ..
Endpoint index: 2 Pipe type: Interrupt Pipe ID: 3.
*/
/*
Device path: \
Device speed: 1 (Low speed).
Endpoint index: 0 Pipe type: Bulk Pipe ID: ..
Endpoint index: 1 Pipe type: Bulk Pipe ID: ..
Endpoint index: 2 Pipe type: Interrupt Pipe ID: 3.
Wrote to pipe 1: 0
Actual data transferred: 1.
Read from pipe 130:
Actual data read: 0.
no error occur!
请按任意键继续. . .
*/
WinUSBeasy
最新推荐文章于 2024-11-22 11:47:12 发布