USB应用程序开发

Posted skdev

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了USB应用程序开发相关的知识,希望对你有一定的参考价值。

 
1 前言
USB开发跟其他文件设备(如串口)开发一样,难点是找到该USB设备的路径,本文以DDK里src/usb/bulkusb例子为参考,阐述一个非HID的USB调试器软件的开发过程。
2 设备GUID
一般设备会有两个GUID, 一个为Class GUID, 在INF文件中,另一个为Device GUID,在SYS文件中。
CreateFile使用的是SYS中的GUID,想得到它有两个办法:
1 跟设备的提供者索要。
2在注册表里找,一般在:
HKEY_LOCAL_MACHINE/SYSTEM/ControlSet001/Control/DeviceClasses/
3 设备路径
根据设备GUID,枚举所有USB HOST,找匹配的USB设备,然后获取其路径。
3.1 头文件 usbport.h
#define WINVER 0x0500
#include <windows.h>
#include <setupapi.h>
#include <basetyps.h>
#include <usbdi.h>
#include <initguid.h>
#include <stdio.h>
 
#pragma comment(lib,"setupapi.lib")
#pragma comment(lib,"hid.lib")
#pragma comment(lib,"comctl32.lib")
 
#ifndef BULKUSBH_INC
#define BULKUSBH_INC
 
#define BULKUSB_IOCTL_INDEX 0x0000
 
 
#define IOCTL_BULKUSB_GET_CONFIG_DESCRIPTOR      CTL_CODE(FILE_DEVICE_UNKNOWN, /
                                                   BULKUSB_IOCTL_INDEX,/
                                                   METHOD_BUFFERED, /
                                                   FILE_ANY_ACCESS)
                                                   
#define IOCTL_BULKUSB_RESET_DEVICE    CTL_CODE(FILE_DEVICE_UNKNOWN, /
                                                   BULKUSB_IOCTL_INDEX+1,/
                                                   METHOD_BUFFERED, /
                                                   FILE_ANY_ACCESS)                                                             
                                                  
#define IOCTL_BULKUSB_RESET_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, /
                                                   BULKUSB_IOCTL_INDEX+2,/
                                                   METHOD_BUFFERED, /
                                                   FILE_ANY_ACCESS)            
extern HANDLE             open_file(char *filename);
extern int                GetUsbPath(char *path);
extern int                WriteUsb(HANDLE hUsb,char *Outbuff, int len);
extern int                ReadUsb(HANDLE hUsb,BYTE inbuff[],DWORD &nBytesRead,int nToRead);
3.2 源文件 usbport.cpp
#include "usbport.h"
 
//8a3bf75d-83c7-440e-8276-5ae3f3ea6e77
DEFINE_GUID(GUID_CLASS_I82930_BULK,0x8a3bf75d, 0x83c7, 0x440e,0x82, 0x76, 0x5a, 0xe3, 0xf3, 0xea, 0x6e, 0x77);
 
BOOL             GetUsbDeviceFileName( LPGUID pGuid, char *outNameBuf);
HANDLE         OpenUsbDevice( LPGUID pGuid, char *outNameBuf);
HANDLE         OpenOneDevice (HDEVINFO HardwareDeviceInfo, PSP_INTERFACE_DEVICE_DATA   DeviceInfoData,char *devName);
int                   GetUsbPath(char *path);
int                   WriteUsb(HANDLE hUsb,char *Outbuff, int len);
int                   ReadUsb(HANDLE hUsb,BYTE inbuff[], DWORD &nBytesRead,int nToRead);
 
/*名称:open_file
 功能:打开USB设备
 参数:filename 定义为”PIPE00” pipe name for bulk input pipe on our test board ,”PIPE01” pipe name for bulk output pipe on our test board。
PIPE00 和 PIPE01 是参考src/usb/bulkusb,我实际在用时这两个效果一样,为了避免USB异常引起的死机,我文件打开采用非阻塞模式。
*/
HANDLE open_file( char *filename)
{
 
       int success = 1;
       HANDLE h;
       char completeDeviceName[256] = ""; //generated from the GUID registered by the driver itself
 
       if ( !GetUsbDeviceFileName((LPGUID) &GUID_CLASS_I82930_BULK,completeDeviceName) )
       {
              //NOISY(("Failed to GetUsbDeviceFileName/n", GetLastError()));
              return INVALID_HANDLE_VALUE;
       }
 
    strcat (completeDeviceName,       "//");                    
 
    strcat (completeDeviceName,       filename);                                  
 
       //printf("completeDeviceName = (%s)/n", completeDeviceName);
 
       h = CreateFile(completeDeviceName,
              GENERIC_WRITE | GENERIC_READ,
              FILE_SHARE_WRITE | FILE_SHARE_READ,
              NULL,
              OPEN_EXISTING,
              FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
              NULL);
 
       if (h == INVALID_HANDLE_VALUE) {
              //NOISY(("Failed to open (%s) = %d", completeDeviceName, GetLastError()));
              success = 0;
       } else {
                     //NOISY(("Opened successfully./n"));
    }           
 
       return h;
}
/*名称:GetUsbDeviceFileName
 功能:获取USB设备路径
 参数:pGUID
 返回:outNameBuf USB设备路径
*/
BOOL GetUsbDeviceFileName( LPGUID pGuid, char *outNameBuf)
{
       HANDLE hDev = OpenUsbDevice( pGuid, outNameBuf );
       if ( hDev != INVALID_HANDLE_VALUE )
       {
              CloseHandle( hDev );
              return TRUE;
       }
       return FALSE;
 
}
/*名称:OpenUsbDevice
 功能:获取 USB设备路径
 参数: pGUID 设备GUID
 返回: outNameBuf USB设备路径
*/
HANDLE OpenUsbDevice( LPGUID pGuid, char *outNameBuf)
{
   ULONG NumberDevices;
   HANDLE hOut = INVALID_HANDLE_VALUE;
   HDEVINFO                 hardwareDeviceInfo;
   SP_INTERFACE_DEVICE_DATA deviceInfoData;
   ULONG                    i;
   BOOLEAN                  done;
   PUSB_DEVICE_DESCRIPTOR   usbDeviceInst;
   PUSB_DEVICE_DESCRIPTOR   *UsbDevices = &usbDeviceInst;
 
   *UsbDevices = NULL;
   NumberDevices = 0;
 
   //
   // Open a handle to the plug and play dev node.
   // SetupDiGetClassDevs() returns a device information set that contains info on all
   // installed devices of a specified class.
   //
   hardwareDeviceInfo = SetupDiGetClassDevs (
                           pGuid,
                           NULL, // Define no enumerator (global)
                           NULL, // Define no
                           (DIGCF_PRESENT | // Only Devices present
                            DIGCF_INTERFACEDEVICE)); // Function class devices.
 
   //
   // Take a wild guess at the number of devices we have;
   // Be prepared to realloc and retry if there are more than we guessed
   //
   NumberDevices = 4;
   done = FALSE;
   deviceInfoData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);
 
   i=0;
   while (!done)
   {
      NumberDevices *= 2;
 
      if (*UsbDevices)
        {
         *UsbDevices = (PUSB_DEVICE_DESCRIPTOR)realloc (*UsbDevices, (NumberDevices * sizeof (USB_DEVICE_DESCRIPTOR)));
      }
        else
        {
         *UsbDevices = (PUSB_DEVICE_DESCRIPTOR)calloc (NumberDevices, sizeof (USB_DEVICE_DESCRIPTOR));
      }
 
      if (NULL == *UsbDevices)
        {
 
         // SetupDiDestroyDeviceInfoList destroys a device information set
         // and frees all associated memory.
 
         SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
         return INVALID_HANDLE_VALUE;
      }
 
      usbDeviceInst = *UsbDevices + i;
 
      for (; i < NumberDevices; i++)
        {
 
         // SetupDiEnumDeviceInterfaces() returns information about device interfaces
         // exposed by one or more devices. Each call returns information about one interface;
         // the routine can be called repeatedly to get information about several interfaces
         // exposed by one or more devices.
 
         if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,
                                         0, // We don't care about specific PDOs
                                                                       pGuid,
                                         i,
                                         &deviceInfoData)) {
 
            hOut = OpenOneDevice (hardwareDeviceInfo, &deviceInfoData, outNameBuf);
                     if ( hOut != INVALID_HANDLE_VALUE )
                     {
               done = TRUE;
               break;
                     }
         }
               else
               {
            if (ERROR_NO_MORE_ITEMS == GetLastError())
                     {
               done = TRUE;
               break;
            }
         }
      }
   }
 
   NumberDevices = i;
 
   // SetupDiDestroyDeviceInfoList() destroys a device information set
   // and frees all associated memory.
 
   SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
   free ( *UsbDevices );
   return hOut;
}
HANDLE OpenOneDevice (
    IN       HDEVINFO                    HardwareDeviceInfo,
    IN       PSP_INTERFACE_DEVICE_DATA   DeviceInfoData,
       IN          char *devName
    )
{
    PSP_INTERFACE_DEVICE_DETAIL_DATA     functionClassDeviceData = NULL;
    ULONG                                predictedLength = 0;
    ULONG                                requiredLength = 0;
       HANDLE                                                        hOut = INVALID_HANDLE_VALUE;
 
    //
    // allocate a function class device data structure to receive the
    // goods about this particular device.
    //
    SetupDiGetInterfaceDeviceDetail (
            HardwareDeviceInfo,
            DeviceInfoData,
            NULL, // probing so no output buffer yet
            0, // probing so output buffer length of zero
            &requiredLength,
            NULL); // not interested in the specific dev-node
 
 
    predictedLength = requiredLength;
    // sizeof (SP_FNCLASS_DEVICE_DATA) + 512;
 
    functionClassDeviceData = (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc (predictedLength);
    functionClassDeviceData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);
 
    //
    // Retrieve the information from Plug and Play.
    //
    if (! SetupDiGetInterfaceDeviceDetail (
               HardwareDeviceInfo,
               DeviceInfoData,
               functionClassDeviceData,
               predictedLength,
               &requiredLength,
               NULL)) {
              free( functionClassDeviceData );
        return INVALID_HANDLE_VALUE;
    }
 
       strcpy( devName,functionClassDeviceData->DevicePath) ;
       //printf( "Attempting to open %s/n", devName );
 
    hOut = CreateFile (
                  functionClassDeviceData->DevicePath,
                  GENERIC_READ | GENERIC_WRITE,
                  FILE_SHARE_READ | FILE_SHARE_WRITE,
                  NULL, // no SECURITY_ATTRIBUTES structure
                  OPEN_EXISTING, // No special create flags
                  0, // No special attributes
                  NULL); // No template file
 
    if (INVALID_HANDLE_VALUE == hOut)
       {
              //printf( "FAILED to open %s/n", devName );
    }
       free( functionClassDeviceData );
       return hOut;
}
/*名称: GetUsbPath
 功能:返回 USB设备路径
 参数: pGUID
 返回: path 路径
*/
int    GetUsbPath(char *path)
{
       if ( !GetUsbDeviceFileName((LPGUID) &GUID_CLASS_I82930_BULK,path) )
       {
              return 0;
       }
       return 1;
}
/*名称: WriteUsb
 功能:向 USB写数据
 参数: hUsb USB句柄,Outbut 数据指针,len 数据长度
*/
int WriteUsb(HANDLE hUsb,char *Outbuff, int len)
{
    DWORD nBytesWrite,endtime,lrc;
    static OVERLAPPED ol;
    DWORD dwErrorMask,dwError;
    COMSTAT comstat;
       if(hUsb==NULL)
              return 0;
    ol.Offset=0; //设备使用指定 0           
    ol.OffsetHigh=0; //设备使用指定 0
    ol.hEvent=NULL;   //标识事件为非信号状态,数据传送完成时,它将被设为信号状态
       ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);   
    if(!WriteFile(hUsb,Outbuff,len,&nBytesWrite,&ol))
    {
       //出错信息处理 --------------------------------
        if((lrc=GetLastError())==ERROR_IO_PENDING)
        {
           endtime=GetTickCount()+1000;
            while(!GetOverlappedResult(hUsb,&ol,&nBytesWrite,FALSE))
            {  
                dwError=GetLastError();
                if(GetTickCount()>endtime)
                {   
                    MessageBox(NULL,"写串口时间过长,目前串口发送缓冲区中的数据数目为空 ",NULL,NULL);
                    break;
                }
                if(dwError=ERROR_IO_INCOMPLETE)
                    continue;          //未完全读完时的正常返回结果
                else
                {
                    //    发生错误,尝试恢复!                    
                    break;
                }
            }
        } 
       //-------------------------------------------------//         
    }   
       CloseHandle(ol.hEvent);
    FlushFileBuffers(hUsb);   
    return 1;
}
/*名称: ReadUsb
 功能:读取 USB设备发来的数据
 参数: hUsb USB句柄,nToRead读取的长度
 返回: inbuff 读到的数据,nBytesRead 读到的长度
*/
int ReadUsb(HANDLE hUsb,BYTE inbuff[], DWORD &nBytesRead,int nToRead)
{
    DWORD lrc;                                 ///纵向冗余校验
    DWORD endtime;                            /jiesuo
    static OVERLAPPED ol;
    int ReadNumber=0;   
    int numCount=0 ;                             //控制读取的数目
    DWORD dwErrorMask;     
       DWORD dwEvtMask=0 ;
       DWORD      ntoread;
       int          ReadTime;
 
    ReadTime=2000;
    ntoread=nToRead;
       ol.Offset=0;                            ///相对文件开始的字节偏移量
    ol.OffsetHigh=0;                        ///开始传送数据的字节偏移量的高位字,管道和通信时调用进程可忽略。
    ol.hEvent=NULL;                         ///标识事件,数据传送完成时设为信号状态
    ol.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
    if(!ReadFile(hUsb,inbuff,ntoread,&nBytesRead,&ol))
    {   
        if((lrc=GetLastError())==ERROR_IO_PENDING)
        {
            ///
            endtime=GetTickCount()+ReadTime;//GetTickCount()取回系统开始至此所用的时间 (毫秒)
            while(!GetOverlappedResult(hUsb,&ol,&nBytesRead,FALSE))//该函数取回重叠操作的结果
            {
                if(GetTickCount()>endtime)
                    break;
            }   
        }       
    }    
       CloseHandle(ol.hEvent);
    return 1;    
}
4 编译前提
开发 USB程序,需要下载Microsotft的DDK(DRIVER DEVELOP KIT)库,该库的配置请参考http://blog.csdn.net/skdev/archive/2007/01/26/1494635.aspx
5 效果
 

以上是关于USB应用程序开发的主要内容,如果未能解决你的问题,请参考以下文章

USB应用程序开发

Linux USB 驱动开发—— 编写USB 驱动程序

MicroPython开发板TPYBoard关于USB-HID的应用

使用 USB 主机模式开发和测试 Android 应用程序

USB开发库文件分析

初涉USB,初学者USB入门总结USB上位机读写开发,请高手指点下!!!