WinUSBeasy

// 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!
请按任意键继续. . .
*/












评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值