基于Cy68013的USB设备在VC程序中热插拔的实现

来源:互联网 发布:php curl get 图片 编辑:程序博客网 时间:2024/05/24 04:27

    开发基于Cy68013的USB设备已经有一段时间,虽然知道它可以支持即插即用,但是一直没有去设计相关的代码,只是在MFC中设计了一个名为“USB连接”的按钮来手动连接到USB设备(参考《USB应用开发技术大全》薛园园编著 人民邮电出版社,2007)。最近又去翻看Cy68013的帮助文档,发现了支持插即用的相关代码,于是试验了一下,基本解决了基于Cy68013的USB设备的PnP功能。

 

    在CyAPI的帮助文件中,对于提供的USB设备类CCyUSBDevice有一段这样的解释:

 

CCyUSBDevice::CCyUSBDevice(HANDLE hnd = NULL, GUID guid = CYUSBDRV_GUID)

* This is the constructor for the CCyUSBDevice class.
* It registers the window of hnd to receive USB Plug and Play messages when devices are onnected or disconnected to/from the driver.
* The object created serves as the programming interface to the driver whose GUID is passed in the guid parameter.

 

    可见,在构建类的对象时给定其HANDLE之后便可以支持USB即插即用。

 

    在CyAPI的帮助文件中还给出了代码示例(虽然是c++ Builder的代码,但对VC程序还是有借鉴作用的)。代码如下:

   void  __fastcall TMainForm::FormCreate(TObject  *Sender)
   {
      USBDevice = new CCyUSBDevice(Handle);
      CurrentEndPt = USBDevice->ControlEndPt;
   }  
   //  Overload MainForm's WndProc method to watch for PnP messages
   //  Requires #include <dbt.h>
   void __fastcall TMainForm::WndProc(TMessage &Message)
   {

     if (Message.Msg == WM_DEVICECHANGE) {

       // Tracks DBT_DEVICEARRIVAL followed by DBT_DEVNODES_CHANGED
       if (Message.WParam == DBT_DEVICEARRIVAL) {
         bPnP_Arrival = true;
         bPnP_DevNodeChange = false;
       }

       // Tracks DBT_DEVNODES_CHANGED followed by DBT_DEVICEREMOVECOMPLETE
       if (Message.WParam == DBT_DEVNODES_CHANGED) {
         bPnP_DevNodeChange = true;
         bPnP_Removal = false;
       }

       if (Message.WParam == DBT_DEVICEREMOVECOMPLETE) {
         bPnP_Removal = true;
 
         PDEV_BROADCAST_HDR bcastHdr = (PDEV_BROADCAST_HDR) Message.LParam;
         if (bcastHdr->dbch_devicetype == DBT_DEVTYP_HANDLE) {

           PDEV_BROADCAST_HANDLE pDev = (PDEV_BROADCAST_HANDLE) Message.LParam;
           if (pDev->dbch_handle == USBDevice->DeviceHandle())
             USBDevice->Close();

         }
       }

       // If DBT_DEVNODES_CHANGED followed by DBT_DEVICEREMOVECOMPLETE
       if (bPnP_Removal && bPnP_DevNodeChange) {
          Sleep(10);
          DisplayDevices();
          bPnP_Removal = false;
          bPnP_DevNodeChange = false;
       }

       // If DBT_DEVICEARRIVAL followed by DBT_DEVNODES_CHANGED
       if (bPnP_DevNodeChange && bPnP_Arrival) {
          DisplayDevices();
          bPnP_Arrival = false;
          bPnP_DevNodeChange = false;
       }

     }

     TForm::WndProc(Message);

   }

    可以看出,程序通过重载WndProc来实现USB设备的相关通知(“Overload MainForm's WndProc method to watch for PnP messages ”), 而在VC下也是有这个函数的,仿照上述代码,可以编写代码如下:

LRESULT C**IDlg::WindowProc(UINT message,WPARAM wParam,LPARAM lParam)

{  
  //   TODO:   在此添加专用代码和/或调用基类  
 if (message == WM_DEVICECHANGE)
 {
       // Tracks DBT_DEVICEARRIVAL followed by DBT_DEVNODES_CHANGED
       if (wParam == DBT_DEVICEARRIVAL)
    {
         bPnP_Arrival = true;
         bPnP_DevNodeChange = false;
       }

       // Tracks DBT_DEVNODES_CHANGED followed by DBT_DEVICEREMOVECOMPLETE
       if (wParam == DBT_DEVNODES_CHANGED)
    {
         bPnP_DevNodeChange = true;
         bPnP_Removal = false;
       }

       if (wParam == DBT_DEVICEREMOVECOMPLETE)
    {
         bPnP_Removal = true;

//       PDEV_BROADCAST_HDR bcastHdr = (PDEV_BROADCAST_HDR) lParam;
//       if (bcastHdr->dbch_devicetype == DBT_DEVTYP_HANDLE)
   {

//           PDEV_BROADCAST_HANDLE pDev = (PDEV_BROADCAST_HANDLE) lParam;
//       DEV_BROADCAST_HDR   *stHDR;  
//    stHDR   =   (DEV_BROADCAST_HDR   *)lParam;     
    
             //if (pDev->dbch_handle == USBDevice->DeviceHandle()) //判断设备类型 
    //if (stHDR->dbch_handle == USBDevice->DeviceHandle())
//             USBDevice->Close();
         }
       }

       // If DBT_DEVNODES_CHANGED followed by DBT_DEVICEREMOVECOMPLETE
       if (bPnP_Removal && bPnP_DevNodeChange)
    {
          Sleep(10);
          DisplayDevices();
          bPnP_Removal = false;
          bPnP_DevNodeChange = false;
       }

       // If DBT_DEVICEARRIVAL followed by DBT_DEVNODES_CHANGED
       if (bPnP_DevNodeChange && bPnP_Arrival)
    {
          DisplayDevices();
          bPnP_Arrival = false;
          bPnP_DevNodeChange = false;
       }

     }

    return   CDialog::WindowProc(message,wParam,lParam);  

}

    然而该段代码并没有指明产生USB消息的设备类型,因此任何USB设备的插拔都会引起程序的相应,为了准确识别到Cy68013的USB设备特别编写了代码中加粗的DisplayDevices(),代码如下:

void CECHWorkStationIIDlg::DisplayDevices()
{
   if(USBDevice->IsOpen())
   {
      USBDevice->Open(0);
      if(!USBDevice->IsOpen())
      {
          USBDevice->Close();
          m_USBStatus = "未连接到仪器";
          UpdateData(FALSE);
         //   MessageBox("USB设备移除。/n","USB connect",MB_OK|MB_ICONERROR);
      }   
   } 
   else
   {
       USBDevice->Open(0);
       if(USBDevice->IsOpen())
       {
           m_USBStatus = USBDevice->DeviceName;
           UpdateData(FALSE);
           if(USBDevice->DeviceCount()>1)
           MessageBox("应用程序不支持多台仪器同时连接到电脑。/n请移除不必要的仪器!/n","出错",MB_OK|MB_ICONERROR);
       }  
   }
}

 

    这样就实现了CY68013设备的热插拔。

    上述内容只是提供了一种解决CY68013 USB设备的一种方法。更多方法欢迎大家一起讨论!