石保敬,王長荀,怯肇乾
?
WinUSB驅(qū)動實現(xiàn)及其通信傳輸應(yīng)用
石保敬,王長荀,怯肇乾
(河南馳誠電氣,河南 鄭州 450001)
微軟近年來推出的規(guī)范簡便的WinUSB設(shè)備通信模型,編程對接的關(guān)鍵是“底層USB設(shè)備如何添加描述使Windows OS識別其為WinUSB設(shè)備”和“可視化測試/應(yīng)用程序怎樣通過WinUSB.dll調(diào)用與之進行管道數(shù)據(jù)傳輸?shù)膶崿F(xiàn)”,恰到好處的運用定時器或線程是異步快速實時數(shù)據(jù)接收軟件設(shè)計的核心,USB測試/應(yīng)用程序發(fā)布針對低級操作系統(tǒng)版本需要編寫引導(dǎo)安裝程序,USB設(shè)備插拔處置和多USB設(shè)備通信的操控也需要特定處置,如此編程設(shè)計,Windows下USB設(shè)備傳輸通信就如同傳統(tǒng)的RS-232C通信一樣方便自如而且還直截了當(dāng)和迅速高效了。
USB描述符;WinUSB設(shè)備;異步數(shù)據(jù)傳輸;定時數(shù)據(jù)接收;線程數(shù)據(jù)接收
Windows操作系統(tǒng)OS(Operation System)下,通過USB(Universal Serial Bus)接口,讀寫訪問USB設(shè)備,是嵌入式應(yīng)用系統(tǒng)和可視化測試/應(yīng)用軟件開發(fā)必不可少的常用環(huán)節(jié)。微軟從Winxp-SP2版本開始,在Windows中集成了通用的WinUSB Device驅(qū)動及其連接OS底層和應(yīng)用層的WinUSB.dll,極大簡化了USB數(shù)據(jù)的通信傳輸。恰到好處的運用WinUSB進行開發(fā),同樣可以到達類似使用傻瓜托管式的WinDriver軟件的效果。編程設(shè)計的關(guān)鍵是如何讓W(xué)indows快速的把USB設(shè)備識別為通用WinUSB設(shè)備和應(yīng)用軟件怎樣合理調(diào)用WinUSB.dll對應(yīng)的WinUSB.lib庫。本文就此展開詳細闡述。
開發(fā)WinUSB驅(qū)動實現(xiàn)及其通信傳輸應(yīng)用,可以采用C++、C#或JavaScript等語言,最好的集成開發(fā)環(huán)境IDE(Integrated Development Environment)是Visial Studio,也可以是Rad Studio XE等,無論哪個IDE都需要首先安裝Windows驅(qū)動程序開發(fā)工具包WDK(Windows Driver Kit)。這里以Rad Studio XE和STM32F103系列微控制器的可視化USB設(shè)備通信開發(fā)為例加以說明。
嵌入式應(yīng)用系統(tǒng)實現(xiàn)USB設(shè)備通信,主要是在高優(yōu)先級的中斷服務(wù)程序中實現(xiàn)的,包括常規(guī)的USB標(biāo)準(zhǔn)請求應(yīng)答和管道讀寫收發(fā)實現(xiàn),管道操作主要是中斷和批量傳輸,USB標(biāo)準(zhǔn)請求包括設(shè)備、配置、接口及其端點描述與速度限定變換。必須設(shè)法讓W(xué)indows識別為通用WinUSB設(shè)備,可視化測試/應(yīng)用程序才可以使用通用的WinUSB設(shè)備驅(qū)動進行溝通交互,如圖1所示。
圖1 通用WinUSB設(shè)備的操作系統(tǒng)識別
為此,需要特別構(gòu)造1個標(biāo)準(zhǔn)USB類描述符--OS描述符和2個供應(yīng)商類描述符--OS特征ID(Identifier)描述符和注冊設(shè)備接口GUID描述符。全球唯一標(biāo)識符GUID(Globally Unique Identifier)。
OS描述符,定義存儲在字符串索引0xEE 處,對應(yīng)的USB標(biāo)準(zhǔn)請求為:
80 06 ee 03 00 00 12 00
典型的OS描述符定義如下:
#define bMS_VendorCode 0x01
//Vendor 請求的請求代碼
const unsigned char OsDscrptStr[] =
// "MSFT100" : index : 0xEE : langId : 0
{ 0x12, 0x03, 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0, bMS_VendorCode, 0 };
供應(yīng)商類OS特征ID描述符,用作設(shè)置擴展兼容,對應(yīng)的供應(yīng)商類請求為:
初步請求--c0 01 00 00 04 00 10 00,再次請求--c0 01 00 00 04 00 28 00
典型的OS特征ID描述符包定義如下:
const unsigned char cptbIdDscrpt [] =
{ 0x28, 0x00, 0x00, 0x00, //包長
0x00, 0x01, //BCD版本
0x04, 0x00, //索引
0x01, //數(shù)量
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, //保留[7]
0x00, //第一接口編號
0x01, //保留(0x01)
'W', 'I', 'N', 'U', 'S', 'B',
0x00, 0x00, //兼容ID[8]
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, //子兼容ID[8]
0x00, 0x00, 0x00,
0x00, 0x00, 0x00 //保留[6]
};
供應(yīng)商類注冊設(shè)備接口GUID,將體現(xiàn)在注冊表中,如圖2所示,GUID可用相應(yīng)工具軟件產(chǎn)生。
圖2 Windows注冊表中的特定通用USB設(shè)備接口GUID示意圖
該描述符,供應(yīng)用程序調(diào)用該GUID做讀寫訪問的USB設(shè)備識別,對應(yīng)的供應(yīng)商類請求為:
初次請求--c1 01 00 00 05 00 0a 00,再次請求--c1 01 00 00 05 00 8e 00
典型的注冊設(shè)備接口 GUID描述符定義如下:
const unsigned char itfcGuidDscrpt[] =
{ 0x8E, 0x00, 0x00, 0x00, //包長(頭+各部分)
0x00, 0x01, //頭: BCD版本
0x05, 0x00, //索引
0x01, 0x00, //數(shù)量
0x84, 0x00, 0x00, 0x00 //部分: 大小
0x01, 0x00, 0x00, 0x00, //屬性數(shù)據(jù)類型
0x28, 0x00, //屬性名字長度
{ 'D', 0, 'e', 0, 'v', 0, 'i', //屬性名稱[40]:
0, 'c', 0, 'e', 0, 'I', 0, "DeviceInterfaceGUID"
'n',0, 't', 0, 'e', 0, 'r',
0, 'f',0, 'a', 0, 'c', 0,
'e', 0, 'G',0, 'U', 0,
'I', 0, 'D', 0, 0, 0
},
0x4E, 0x00, //屬性數(shù)據(jù)長度:
0x00, 0x00, 78[0x4E]
{ '{', 0, '1', 0, '2', 0, '3', 0, //屬性數(shù)據(jù): {12345678-
'4', 0, '5', 0, '6', 0, '7', 1234-1234-1234-
0, 8', 0, '-', 0, '1', 0, '2', 123456789ABC}
0, '3', 0, '4', 0, '-', 0, '1',
0, '2', 0, '3', 0, 4', 0, ' '-',
0, '1', 0, '2', 0, '3', 0, '4',
0, '-', 0, '1', 0,'2', 0, '3', 0,
'4', 0, '5', 0, '6', 0, '7', 0,
8', 0, '9', 0, 'A', 0, 'B', 0,
'C', 0, '}', 0, 0, 0
}
};
可用作者的“ARM系列微處理控制器的軟件體系架構(gòu)工具”得到完整的STM32103系列USB驅(qū)動程序,包括上述3個特殊描述符在內(nèi)的標(biāo)準(zhǔn)USB請求類和供應(yīng)商請求及其應(yīng)答配置與控制、中斷、批量或同步管道傳輸代碼,限于篇幅,不再贅述。
可視化測試/應(yīng)用程序中使用Windows OS通用的WinUSB設(shè)備驅(qū)動,必須引入對WDK頭文件的引用,需要在可視化窗口.cpp文件頭部加入的典型.h文件引用如下:
#include "Windows Kits10Include10.0.15063. 0sharedusb.h"
#include "Windows Kits10Include10.0.15063. 0sharedstrsafe.h"
#include "Windows Kits10Include10.0.15063. 0umSetupAPI.h"
#include "Windows Kits10Include10.0.15063. 0umwinusb.h"
可視化測試/應(yīng)用程序,通過連接OS底層和應(yīng)用層的WinUSB.dll操作特定的通用WinUSB Device,必須在項目工程中引用WinUSB.dll對應(yīng)的WinUSB.lib庫文件。WDK提供有相應(yīng)的WinUSB. lib,在Visival Studio中引用沒有問題,但不能直接在Rad Studio XE中引用,編譯連接時會報錯:
BCB contains invalid OMF record, type 0x21 (possibly COFF)
這是IDE要求的原始設(shè)備制造商OEM(Original Equipment Manufacturer)的通用對象文件格式COFF(Common Object File Format)不同引起的lib文件兼容不足導(dǎo)致的??梢允褂肦ad Studio XE的coff2omf. exe工具進行轉(zhuǎn)換再加以引用,命令行操作如下,其中前者是微軟DDK提供的,后者就是得到的Rad Studio XE開發(fā)所需的庫:
coff2omf -lib:ms WinUSB.lib bcb WinUSB.lib
與其它OS一樣,Winsows把設(shè)備當(dāng)做文件操作,但USB設(shè)備又有特定的集成端點在內(nèi)的管道傳輸?shù)慕涌冢源蜷_USB設(shè)備文件后還要打開相應(yīng)的USB接口,得到特定的USB接口操作句柄,之后就可以運用該句柄,調(diào)用管道讀寫進行數(shù)據(jù)傳輸了??梢暬瘻y試/應(yīng)用程序退出時必須依次關(guān)閉USB接口操作句柄和設(shè)備文件操作句柄。
獲取USB設(shè)備及其接口操作句柄的典型函數(shù)代碼如下:
HANDLE hDeviceHandle = INVALID_HANDLE_VALUE; // 設(shè)備文件句柄
WINUSB_INTERFACE_HANDLE hWinUSBHandle // WinUSB操作句柄
= INVALID_HANDLE_VALUE;
// USB設(shè)備文件句柄創(chuàng)建[接口GUID,設(shè)備句柄]-------------------------------------------------------------------
BOOL GetDeviceHandle(GUID guidDeviceInterface, PHANDLE hDeviceHandle )
{ if ( guidDeviceInterface == GUID_NULL ) return FALSE;
BOOL bResult = TRUE; HDEVINFO hDeviceInfo;
SP_DEVINFO_DATA DeviceInfoData; DWORD index = 0;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = NULL;
ULONG requiredLength = 0; LPTSTR lpDevicePath = NULL;
// 為特定設(shè)備的接口類而獲取安裝設(shè)備的所有信息
hDeviceInfo = SetupDiGetClassDevs(&guidDeviceInterface, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
if ( hDeviceInfo == INVALID_HANDLE_VALUE ) goto done; // 無效退出
// 在設(shè)備信息集中枚舉所有設(shè)備接口
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for(index=0; SetupDiEnumDeviceInfo(hDeviceInfo, index, & DeviceInfoData); index++)
{ if(lpDevicePath) LocalFree(lpDevicePath); // 復(fù)位相應(yīng)項
if(pInterfaceDetailData) LocalFree(pInterfaceDetailData);
deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
bResult = SetupDiEnumDeviceInterfaces( hDeviceInfo, // 獲取設(shè)備接口信息
&DeviceInfoData, &guidDeviceInterface, 0, &deviceInterfaceData );
if(GetLastError()== ERROR_NO_MORE_ITEMS) break; // 最后項?
if(!bResult) goto done; // 錯誤退出
// 動態(tài)調(diào)用2次,首次分配空間,再次得到接口數(shù)據(jù)
bResult = SetupDiGetDeviceInterfaceDetail( hDeviceInfo,
&deviceInterfaceData, NULL, 0, &requiredLength, NULL );
if(!bResult) // 錯誤檢查
{ if((ERROR_INSUFFICIENT_BUFFER == GetLastError())
&& ( requiredLength > 0 ) )
{ pInterfaceDetailData = // 動態(tài)分配緩沖區(qū)大小
(PSP_DEVICE_INTERFACE_DETAIL_DATA)
LocalAlloc(LPTR, requiredLength );
if (!pInterfaceDetailData ) goto done; // 錯誤退出
}
else goto done; // 錯誤退出
}
pInterfaceDetailData->cbSize // 獲取接口詳細數(shù)據(jù)
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
bResult = SetupDiGetDeviceInterfaceDetail( hDeviceInfo,
&deviceInterfaceData, pInterfaceDetailData,
requiredLength, NULL, &DeviceInfoData );
if (!bResult) goto done; // 錯誤退出
size_t nLength = wcslen(pInterfaceDetailData->DevicePath ) + 1; // 設(shè)備文件路徑
lpDevicePath = (TCHAR *) LocalAlloc( LPTR, nLength * sizeof(TCHAR));
StringCchCopy(lpDevicePath, nLength, pInterfaceDetailData->DevicePath);
lpDevicePath[(nLength - 1)] = 0;
}
if (!lpDevicePath) goto done; // 錯誤退出
}
*hDeviceHandle = CreateFile( lpDevicePath, // 打開設(shè)備文件, 得到設(shè)備文件句柄
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ
| FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
if (*hDeviceHandle != INVALID_HANDLE_VALUE ) return true;
done: LocalFree( lpDevicePath );
LocalFree( pInterfaceDetailData );
bResult = SetupDiDestroyDeviceInfoList( hDeviceInfo );
return bResult;
}
// 獲取設(shè)備的 WinUSB 接口句柄------------------------------------------------------------------------------------
BOOL GetWinUSBHandle(HANDLE hDeviceHandle,
PWINUSB_INTERFACE_HANDLE phWinUSBHandle)
{ if(hDeviceHandle == INVALID_HANDLE_VALUE) return FALSE;
BOOL bResult = WinUsb_Initialize(hDeviceHandle, phWinUSBHandle);
if (!bResult) return FALSE;
return bResult;
}
可視化窗口,創(chuàng)建時運用特定USB接口GUID,調(diào)用這兩個函數(shù)創(chuàng)建設(shè)備文件句柄和USB接口操作句柄;窗口關(guān)閉時依次關(guān)閉這兩個句柄;若USB設(shè)備沒有掛接,應(yīng)用禁止窗口上所有USB數(shù)據(jù)收發(fā)按鈕操作,相關(guān)核心代碼如下:
void__fastcall TfrmShow::FormCreate(TObject *Sender)
{static const GUID stm32F1xxDvcItfc = { 0x-12345678, 0x1234, 0x1344,
{0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC } };
GUID guidDeviceInterface = stm32F1xxDvcItfc;
BOOL bResult = TRUE; ULONG cbSize = 0;
bResult = GetDeviceHandle(guidDeviceInterface, &hDeviceHandle);
if (!bResult) return;
bResult = GetWinUSBHandle(hDeviceHandle, & hWinUSBHandle);
if(!bResult) return;
flgWinUSB = true;
}
//---------------------------------------------------------
void __fastcall TfrmShow::FormClose(TObject *Sender, TCloseAction &Action)
{ if(!flgWinUSB) return;
CloseHandle(hDeviceHandle);
WinUsb_Free(hWinUSBHandle);
}
運用WinUSB應(yīng)用程序編程接口API (Appli-cation Programming Interface)函數(shù)WinUsb_ReadPipe和WinUsb_WritePipe進行數(shù)據(jù)管道收發(fā)傳輸時,若沒有收到或發(fā)出數(shù)據(jù),程序會一直等待,造成可視化窗口失控,可以通過調(diào)用WinUsb_SetPipePolicy函數(shù),使用WinUSB的超時管道傳輸策略來避免這種阻塞式的尷尬局面,取消請求之前等待超時時間,超過超時時間退出等待。通常在USB設(shè)備文件句柄和WinUSB接口句柄創(chuàng)建成功后進行超時傳輸設(shè)置,時間據(jù)實際傳輸量而定,典型代碼如下,這里超時時間取100ms,0x81對應(yīng)輸入IN管道1,0x02對應(yīng)輸出OUT管道2:
UINT timeout = 100;
bResult = WinUsb_SetPipePolicy(hWinUSBHandle, 0x81, // 輸入IN管道1
PIPE_TRANSFER_TIMEOUT, sizeof (timeout), & timeout);
if(!bResult) return;
bResult = WinUsb_SetPipePolicy(hWinUSBHandle, 0x02, // 輸出OUT管道2
PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout);
if(!bResult) return;
數(shù)據(jù)發(fā)送,同異步操作差別不大,只要準(zhǔn)備好數(shù)據(jù),很容易知道其數(shù)據(jù)大小,主動同步發(fā)出,以最簡方式實現(xiàn),典型代碼如下:
if(hWinUSBHandle==INVALID_HANDLE_VALUE) return;
UCHAR szBffr[50]; ULONG cbSent = 0;
AnsiString str = edtSdDt->Text; // 窗口文本輸入控件
strcpy(szBffr, str.c_str());
ULONG cbSize = str.Length();
WinUsb_WritePipe(hWinUSBHandle, 0x02, szBffr, cbSize, &cbSent, 0 );
異步數(shù)據(jù)收發(fā)傳輸,對于不知數(shù)據(jù)量大小的操作非常有效,特別是USB管道的讀操作。
首先需要定義全局的OVERLAPPED結(jié)構(gòu)變量,并在USB設(shè)備文件及其WinUSB接口句柄創(chuàng)建成功后初始化這個結(jié)構(gòu)變量,主要是其相關(guān)“事件Event”的初始化,典型代碼如下:
OVERLAPPED overlapped;
ZeroMemory(&overlapped, sizeof(overlapped));
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
典型的異步USB管道讀事件代碼如下,首先以小固定數(shù)量15進行盲讀,在限定的超時時間內(nèi),只要收到數(shù)據(jù),都可以接收,并成行顯示在窗口的文本指示框內(nèi):
void WinUSB_Read(void)
{ if(hWinUSBHandle==INVALID_HANDLE_VALUE) return;
ULONG cbRead = 0; UCHAR szBffr[20] = {'0'}; AnsiString str;
BOOL bResult = WinUsb_ReadPipe(hWinUSB-Handle, 0x81,
szBffr, 15, &cbRead, &overlapped);
if(bResult)
{ const char* t = szBffr; str = t;
mRcvDt->Lines->Add(str); // 可視窗口文本顯示控件
}
else if(ERROR_IO_PENDING == GetLastError ())
{bResult = WinUsb_GetOverlappedResult(hW-inUSBHandle, & overlapped, &cbRead, true);
if(NULL != cbRead)
{ int m = cbRead; cbRead = 0;
if(bResult)
{ const char* d = szBffr; str = d;
mmRcvDt->Lines->Add(str);
}
}
}
}
隨時監(jiān)聽USB輸入管道并接收可能傳入的數(shù)據(jù),在可視化測試/應(yīng)用程序設(shè)計中,簡潔高效的方法就是采用定時器控制,以一定的時間間隔,在定時器的OnTimer事件處理中,去異步的讀取USB輸入管道,典型代碼如下,其中設(shè)置的時間間隔是100 ms:
void __fastcall TfrmShow::rcvTmrTimer(TObject *Sender)
{ rcvTmr->Enabled = false; // 關(guān)閉定時器
WinUSB_Read(); // 異步數(shù)據(jù)謀取并進行可視化窗口顯示
rcvTmr->Enabled = true; // 重開定時器
}
以線程方式在后臺進行USB輸入管道的監(jiān)聽并接收可能傳入的數(shù)據(jù),是另外一種及時高效的USB數(shù)據(jù)接收形式。在項目工程中新建線程對象rcvThrd,進而在生成的rcvThrd.h文件中聲明引用的窗口顯示控件和數(shù)據(jù)接收函數(shù)RcvDt(),典型代碼如下:
class thrdRcvDt : public TThread
{ private: TMemo *memo;
protected: void __fastcall Execute();
public: void __fastcall thrdRcvDt::RcvDt();
__fastcall thrdRcvDt(bool CreateSuspended, TMemo *Amemo);
};
在rcvThrd.cpp文件中,聲明所需的包含文件、外部變量,并定義操作函數(shù),典型代碼如下:
#include "frmStm32Tst.h" // 可視化窗口文件
#include "Windows Kits10Include10.0.15063. 0sharedusb.h" // DDK文件
#include "Windows Kits10Include10.0.15063. 0sharedstrsafe.h"
#include "Windows Kits10Include10.0.15063. 0umSetupAPI.h"
#include "Windows Kits10Include10.0.15063. 0umwinusb.h"
extern WINUSB_INTERFACE_HANDLE hWin-USBHandle;
extern OVERLAPPED overlapped;
extern void WinUSB_Read(void);
__fastcall thrdRcvDt::thrdRcvDt(bool Create-Suspended, TMemo *Amemo) : TThread(CreateSu-spended)
{ memo = Amemo; }
void __fastcall thrdRcvDt::Execute() // 線程執(zhí)行[休眠100ms]
{ while(!Terminated)
{ Synchronize(RcvDt); Sleep(100); }
}
void __fastcall thrdRcvDt::RcvDt() // 數(shù)據(jù)異步接收窗口指示
{ WinUSB_Read(); }
在可視化窗口的frmStm32Tst.h中加入線程對象包含和線程實例化聲明,典型代碼如下:
#include "rcvThrd.h"
class TfrmShow : public TForm
{ …
private: thrdRcvDt *rcvThrd;
…
}
在可視化窗口的frmStm32Tst.cpp中,打開設(shè)備文件和WinUSB接口句柄后,啟動線程,定義線程終止時自動銷毀,然后運行線程,典型代碼如下:
rcvThrd = new thrdRcvDt(true, mmRcvDt);
rcvThrd->FreeOnTerminate = true;
rcvThrd->Resume();
對比定時數(shù)據(jù)接收,異曲同工。定時器控件,本質(zhì)就是休眠時間可調(diào)整的線程操作封裝。
以上闡述基于先插上USB設(shè)備,再打開可視化測試/應(yīng)用程序,進行通信傳輸,用后關(guān)閉應(yīng)用程序,撥下設(shè)備。而USB設(shè)備即插即用,在USB設(shè)備突然被拔下后,還進行讀寫傳輸,程序就阻塞了。為避免這種現(xiàn)象發(fā)生,可創(chuàng)建一個線程,定時(如每2s)枚舉檢查相關(guān)的USB設(shè)備,若被拔下,停止定時數(shù)據(jù)接收或休眠接收線程;若重新插入,則重新創(chuàng)建操作句柄,恢復(fù)定時數(shù)據(jù)接收或線程數(shù)據(jù)接收。
應(yīng)用軟件發(fā)布,除Rad Studio產(chǎn)生的.exe文件外,還需要包含WinUSB.lib。若編譯時不能包含動態(tài)庫,還需要包含IDE相關(guān)的cc32240mt.dll和borlndmm.dll。上述各種方法綜合在一起,得到的針對STM32F103系列微控制USB設(shè)備的WinUSB數(shù)據(jù)收發(fā)測試的可視化應(yīng)用程序窗口界面如圖3所示:
圖3 WinUSB數(shù)據(jù)收發(fā)測試的可視化應(yīng)用程序窗口界面
編寫驅(qū)動安裝文件.inf,引導(dǎo)OS調(diào)用內(nèi)置的winusb.sys驅(qū)動文件的安裝應(yīng)用,主要指明USB設(shè)備的廠商號、產(chǎn)品號、USB接口GUID等,通知安裝程序類已設(shè)置為 "USBDevice"。需要使用WinUSB協(xié)助安裝庫文件WinUsbCoInstaller,區(qū)分32位和64位版本,常用版本是V1.9,Win7之后也可以是V1.11。Win7之后系統(tǒng),還需要準(zhǔn)備cat文件,可運用WDK的Inf2Cat.exe工具得到,命令行操作如下:
Inf2Cat.exe /driver:[inf文件目錄] /os: XP_X86, XP_X64,7_X86,7_X64,8_X32,8_X64
典型inf驅(qū)動安裝文件如下:
[Version]
Signature="$Windows NT$"
Class=USBDevice
ClassGUID={88BAE032-5A81-49f0-BC3D-A4-FF138216D6}
Provider=%ManufacturerName%
CatalogFile=instlWinUSB.cat
DriverVer=01/13/2018,12.4.23.896
[Manufacturer]
%ManufacturerName%=Standard,NTx86,NTx64
[Standard.NTx86]
%DeviceName%=USB_Install,USBVID_0483& PID_5720
[Standard.NTx64]
%DeviceName%=USB_Install,USBVID_0483& PID_5720
[ClassInstall32]
AddReg=ClassInstall_AddReg
[ClassInstall_AddReg]
HKR,,,,%ClassName%
HKR,,NoInstallClass,,1
HKR,,IconPath,%REG_MULTI_SZ%,"C:WindowsSystem32setupapi.dll,-20"
HKR,,LowerLogoVersion,,5.2
[USB_Install]
Include=winusb.inf
Needs=WINUSB.NT
[USB_Install.Services]
Include=winusb.inf
AddService=WinUsb,0x00000002,WinUsb_Ser-viceInstall
[WinUsb_ServiceInstall]
DisplayName=%WinUsb_SvcDesc%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=C:WindowsSystem32driversWin--USB.sys
[USB_Install.HW]
AddReg=Dev_AddReg
[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{12345678-1234-1344-1234-123456789ABC}"
[USB_Install.Wdf]
KmdfService=WINUSB, WinUsb_Install
[WinUSB_Install]
KmdfLibraryVersion=1.9
[USB_Install.CoInstallers]
AddReg=CoInstallers_AddReg
CopyFiles=CoInstallers_CopyFiles
[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01009.dll,WdfCoInstaller"
[CoInstallers_CopyFiles]
WdfCoInstaller01009.dll
[DestinationDirs]
CoInstallers_CopyFiles=11
[SourceDisksNames]
1=%DiskName%
[SourceDisksFiles]
WdfCoInstaller01009.dll=1
[Strings]
ManufacturerName="STMicroelectronics"
ClassName="USB通用串行總線設(shè)備"
DiskName="kzq"
WinUsb_SvcDesc="WinUSB Driver"
DeviceName="STM3210"
REG_MULTI_SZ = 0x00010000
多個同類WinUSB設(shè)備插入同一臺電腦,系統(tǒng)都可以識別,通信時連接傳輸快的USB設(shè)備占主動權(quán)后,其它USB設(shè)備就不通信了??梢孕薷腢SB設(shè)備的接口GUID,使連入USB設(shè)備差異化,以實現(xiàn)各個對應(yīng)的傳輸通信,找到一個設(shè)備通信一個,從而實現(xiàn)類似設(shè)備參數(shù)配置的批量操作實現(xiàn)。
表1 幾種驅(qū)動及其開發(fā)對比表
Tab.1 Some kind of device drivers and it’s design comparison
底層嵌入式應(yīng)用軟件中添加特定描述支持,Windows OS就可以自動識其為WinUSB設(shè)備,上層可視化測試/應(yīng)用程序就可以通過WinUSB.dll與其進行USB數(shù)據(jù)傳輸通信了。這樣,Windows下USB設(shè)備的數(shù)據(jù)采集、監(jiān)視控制、配置參數(shù)、軟件刷新等軟件編程操控,就同傳統(tǒng)的“RS-232C通信”一樣了,無需USB轉(zhuǎn)串口硬軟件轉(zhuǎn)接,而且速度快、實時性強,直截了當(dāng)。同樣,定時接收、線程接收、多設(shè)備通信等軟件手段也可以搬來使用,進一步提升效率和實用性。
[1] CSDN博客. USB設(shè)備描述符舉例說明[EB/OL]. http://blog. csdn.net/u013256018/article/details/60805770?locationNum=10&fps=1, 2017.3.
[2] CSDN博客﹒WinUSB--微軟為所有USB設(shè)備提供的常規(guī)驅(qū)動程序[EB/OL]. http://blog.csdn.net/whw8007/article/details/ 9569989, 2013.8.
[3] 微軟開發(fā)網(wǎng). 如何通過WinUSB功能訪問USB設(shè)備[EB/OL]. https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff540174(v=vs.85).aspx, 2017.12.
[4] 馬開東博客. 如何使用WinUSB與USB設(shè)備USBDevice通信[EB/OL]. http://www.makaidong.com/%E5%8D%9A%E5% AE%A2%E5%9B%AD7/20151013/306670_4.html, 2015.10.
[5] 微軟開發(fā)網(wǎng). 適用于USB設(shè)備的Windows桌面應(yīng)用[EB/OL]. https://msdn.microsoft.com/zh-cn/library/windows/ hardware/dn376885(v=vs.85).aspx, 2017.12.
[6] 微軟開發(fā)網(wǎng). 編寫基于WinUSB模板的Windows桌面應(yīng)用[EB/OL]. https://msdn.microsoft.com/zh-cn/library/windows/ hardware/dn376872(v=vs.85).aspx, 2017.12.
[7] 微軟開發(fā)網(wǎng). 用于管道策略修改的WinUSB功能[EB/OL]. https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff728833(v=vs.85).aspx, 2017.12.
[8] 怯肇乾等. Windows異步串行通信編程縱橫[J]. 電腦與開發(fā)應(yīng)用, 2009, 6(445): 21-25.
[9] CSDN博客. winusb--不再為你的usb設(shè)備編寫驅(qū)動[EB/OL]. https://blog.csdn.net/phenixyf/article/details/46744419, 2015.7.
[10] 彭偉. 基于WinUSB與SHT75的溫濕度數(shù)據(jù)采集與控制系統(tǒng)設(shè)計仿真[J]. 制造業(yè)自動化, 2013, 7(15): 129-133.
Implementation of WinUSB Driver and Its Application in Communication Transmission
SHI Bao-jing, WANG Chang-xun, KAI Zhao-qian
(HNCC Electronic Co., LTD, Zhengzhou 450001, China)
Software design key about WinUSB-Device-Model-Application is how to add descriptor to WinUSB-Device in Windows OS and how to communicate in Windows Application. It’s kernel is how to use timer and thread with asynchronous-data-transmission. Note WinUSB-Application-Publishing in low operating system version, account USB-Plug-in-Plug-out handling and multi-USB-devices-communication. So, Windows USB device data transmission are easy to use such as RS-232C.
USB descriptor; WinUSB device; Asynchronous data transmission; Data reception with timer; Data reception with thread.
TP36
B
10.3969/j.issn.1003-6970.2018.08.013
怯肇乾(1969-),男,電子與信息技術(shù)高級工程師,嵌入式系統(tǒng)設(shè)計師/培訓(xùn)師,web網(wǎng)絡(luò)測控軟件系統(tǒng)架構(gòu)師,研究方向為軟硬件體系及其網(wǎng)絡(luò)系統(tǒng)軟件設(shè)計;石保敬(1977-),男,經(jīng)濟師,風(fēng)險評估師,環(huán)保健康探測警報專家,研究方向為危害和易燃易爆氣體探測產(chǎn)品系統(tǒng)及其開發(fā)設(shè)計;王長荀(1988-),男,嵌入式硬軟件開發(fā)工程師,研究方向為軟硬件體系及其網(wǎng)絡(luò)系統(tǒng)軟件設(shè)計。
本文著錄格式:石保敬,王長荀,怯肇乾. WinUSB驅(qū)動實現(xiàn)及其通信傳輸應(yīng)用[J]. 軟件,2018,39(8):57-64