[转]C++ MFC界面读写USB HID设备数据程序
(2015-10-10 12:56:36)
标签:
it |
分类: 编程心得 |
C++ MFC界面读写USB HID设备数据程序
跟大家分享一个最近开发的,用来测试USB HID设备的通用程序,程序还有很多可以继续优化的地方,比如说interupt的周期,读取字节的多少等。
我遇到的问题是:开发一个简单易用的界面,用来对USB HID设备(比如说游戏手柄,控制面板等)读写数据,一般情况下面板上有一些LED,可以帮助我们测试读写是否正确。另外,需要可以修改vendorID和prodcutID,这样一个界面,可以用于测试多个HID设备。
过程分成3步:1: 列举出所有的HID设备,2: 循环读取HID设备数据,3: 向HID设备写数据,下面我把三部分的程序单独分开,方便大家学习!
在讲具体程序之前,先说一下visual studio的环境配置(我用的是2008版本)!
首先建立一个MFC dialog程序,然后进行配置。
Tools->Options->VC++ Directories Platform (Win32)
跟大家分享一个最近开发的,用来测试USB HID设备的通用程序,程序还有很多可以继续优化的地方,比如说interupt的周期,读取字节的多少等。
我遇到的问题是:开发一个简单易用的界面,用来对USB HID设备(比如说游戏手柄,控制面板等)读写数据,一般情况下面板上有一些LED,可以帮助我们测试读写是否正确。另外,需要可以修改vendorID和prodcutID,这样一个界面,可以用于测试多个HID设备。
过程分成3步:1: 列举出所有的HID设备,2: 循环读取HID设备数据,3: 向HID设备写数据,下面我把三部分的程序单独分开,方便大家学习!
在讲具体程序之前,先说一下visual studio的环境配置(我用的是2008版本)!
首先建立一个MFC dialog程序,然后进行配置。
Tools->Options->VC++ Directories Platform (Win32)
第一步:列举所有的HID设备:
m_ctllHIDdevices.ResetContent(); //这是MFC里面一个list控件,用来显示所有的HID设备的,如果你没有界面,可以不需要此行
UpdateData(FALSE); //更新界面
CString temp;
int Count = 0; //Total number of devices found
DWORD strSize=0,requiredSize=0;
BOOL result1,result2;
ULONG DeviceInterfaceDetailDataSize;
//定义一些变量,以后会用到
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
//PSP_DEVICE_INTERFACE_DETAIL_DATA test;
//第一步:获取deviceID
GUID deviceId;
HidD_GetHidGuid(&deviceId);
//第二步:获取设备信息
HDEVINFO handle;
handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices
//第三步:对所有的设备进行枚举
//SetupDiEnumDeviceInterfaces();
result1=false; //定义一些变量
result2=false;
CString temp11="";
do
{
DeviceInterfaceData.cbSize
= sizeof(SP_DEVICE_INTERFACE_DATA);
result1 =
SetupDiEnumDeviceInterfaces(
handle,
NULL, // IN
PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
&deviceId,
Count,
&DeviceInterfaceData
);
//获得设备详细数据(初步)
SetupDiGetDeviceInterfaceDetail(handle,
&DeviceInterfaceData,
NULL,
0,
&strSize,
NULL);
requiredSize=strSize;
DeviceInterfaceDetailData=(PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requiredSize);
DeviceInterfaceDetailData->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
DeviceInfoData.cbSize=sizeof(SP_DEVINFO_DATA);
//再次获得详细数据
result2=SetupDiGetDeviceInterfaceDetail(handle,
&DeviceInterfaceData,
DeviceInterfaceDetailData,
strSize,
&requiredSize,
&DeviceInfoData);
//获得设备路径(最重要的部分)
temp=DeviceInterfaceDetailData->DevicePath;
UpdateData(FALSE);
m_ctllHIDdevices.AddString(temp);
Count++;
} while
(result1);
UpdateData(false);
到这个时候为止,所有的设备路径,都会显示在窗口的listbox里面!
m_ctllHIDdevices.ResetContent(); //这是MFC里面一个list控件,用来显示所有的HID设备的,如果你没有界面,可以不需要此行
UpdateData(FALSE); //更新界面
CString temp;
int Count = 0; //Total number of devices found
DWORD strSize=0,requiredSize=0;
BOOL result1,result2;
ULONG DeviceInterfaceDetailDat
//定义一些变量,以后会用到
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVICE_INTERFACE_DATA
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailDat
//PSP_DEVICE_INTERFACE_DETAIL_DATA test;
//第一步:获取deviceID
GUID deviceId;
HidD_GetHidGuid(&deviceId);
//第二步:获取设备信息
HDEVINFO handle;
handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices
//第三步:对所有的设备进行枚举
//SetupDiEnumDeviceInterfa
result1=false; //定义一些变量
result2=false;
CString temp11="";
do
{
到这个时候为止,所有的设备路径,都会显示在窗口的listbox里面!
第二步:循环读取HID设备数据(根据用户提供的HID的vendorID和productID),并且把字节解码成二进制,在MFC界面上用LED展示:
为了不影响主线程的运行,我把读取数据的操作,放在一个子线程里!每隔50ms去读取一次数据!
首先创建一个线程:
HANDLE
hThread1;
bStopHID=false;
//这个变量,以后用来停止线程
UpdateData(true);
//更新界面,获取变量
UpdateData(false);
hThread1 =
CreateThread(NULL,0,Thread_Enable_Read,(LPVOID)this, NULL,
NULL);
在线程的程序里:
CusbhidDlg *p = ( CusbhidDlg *)pvParam;
//获取主窗口的指针,用来调用主窗口的变量和函数
p->UpdateData(true);
p->bStopHID=false;
CString
temp;
CString
DevicePath;
temp="";
int Count =
0; //Total number of devices found
DWORD
strSize=0,requiredSize=0;
BOOL
result1,result2;
ULONG
DeviceInterfaceDetailDataSize;
SP_DEVINFO_DATA
DeviceInfoData;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA
DeviceInterfaceDetailData;
//PSP_DEVICE_INTERFACE_DETAIL_DATA
test;
//1
GUID
deviceId;
HidD_GetHidGuid(&deviceId);
int
venderID=p->v_eVendorID; //从窗口里获取用户输入的VendorID
int
productID=p->v_eProductID; //从窗口里获取用户输入的ProductID
unsigned char
inbuffer[2]; //用来存放读取的数据,请在这里定义你自己需要的长度,我每次读一个字节进来
unsigned long
numBytesReturned;
HIDD_ATTRIBUTES
devAttr;
PHIDP_PREPARSED_DATA
PreparsedData;
HIDP_CAPS
Capabilities;
int
readValue;
bool
LED;
int
flag=0;
//2
HDEVINFO
handle;
handle =
SetupDiGetClassDevs(&deviceId, NULL, NULL,
DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID
devices
int
i=0;
int
j=p->m_ctllHIDdevices.GetCount();
for
(i=0;im_ctllHIDdevices.GetCount();i++)
{
p->m_ctllHIDdevices.GetText(i,temp);
DevicePath=temp;
//CreateFile是非常重要的一步,用来建立于HID通信的句柄
HANDLE hCom
= CreateFile (
DevicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING, 0,
NULL);
if (hCom ==
INVALID_HANDLE_VALUE)
{
//AfxMessageBox("Invalide Device Path...");
continue;
}
devAttr.Size=sizeof(HIDD_ATTRIBUTES);
if
(!HidD_GetAttributes(hCom,&devAttr))
{
CloseHandle(hCom);
AfxMessageBox("Cannot get the parameters of the
HID...");
return
0;
}
//temp.Format("Vendor ID: %d, Product
ID:%d",devAttr.VendorID,devAttr.ProductID); //Compare with the
Vendor ID and Product ID from Nakamura-san
//AfxMessageBox(temp);
if
(!HidD_GetPreparsedData(hCom,&PreparsedData))
{
CloseHandle(hCom);
AfxMessageBox("Cannot get the Preparsed
Data...");
return
0;
}
if(!HidP_GetCaps(PreparsedData,&Capabilities))
{
CloseHandle(hCom);
AfxMessageBox("Cannot get the Cap
Data...");
return
0;
}
if
(devAttr.VendorID == venderID && devAttr.ProductID ==
productID)
{
while(1)
{
result1 =
ReadFile(hCom, &inbuffer[0],
Capabilities.InputReportByteLength, &numBytesReturned,
0);
temp=inbuffer;
//p->m_eDataRead=CString(inbuffer);
//p->UpdateData(false);
if(!result1)
{
AfxMessageBox("Cannot Read
Data...");
return
0;
}
readValue=inbuffer[1];
p->m_eDataRead.Format("%d",readValue);
//下面是我把数据从10进制转换成二进制,并且点亮LED
(一个字节有8个bits,可以点亮8个LED
for (int
k=0;k<8;k++)
{
flag=readValue%2;
readValue=readValue/2;
if
(k==0)
{
if
(flag==0)
p->m_sDynLED0.SwitchOff();
else
p->m_sDynLED0.SwitchOn();
}
else if
(k==1)
{
if
(flag==0)
p->m_sDynLED1.SwitchOff();
else
p->m_sDynLED1.SwitchOn();
}
else if
(k==2)
{
if
(flag==0)
p->m_sDynLED2.SwitchOff();
else
p->m_sDynLED2.SwitchOn();
}
else if
(k==3)
{
if
(flag==0)
p->m_sDynLED3.SwitchOff();
else
p->m_sDynLED3.SwitchOn();
}
else if
(k==4)
{
if
(flag==0)
p->m_sDynLED4.SwitchOff();
else
p->m_sDynLED4.SwitchOn();
}
else if
(k==5)
{
if
(flag==0)
p->m_sDynLED5.SwitchOff();
else
p->m_sDynLED5.SwitchOn();
}
else if
(k==6)
{
if
(flag==0)
p->m_sDynLED6.SwitchOff();
else
p->m_sDynLED6.SwitchOn();
}
else if
(k==7)
{
if
(flag==0)
p->m_sDynLED7.SwitchOff();
else
p->m_sDynLED7.SwitchOn();
}
}
p->UpdateData(false);
::Sleep(50);
//判断用户是否点击停止按钮,若是,则退出
if(p->bStopHID)
{
AfxMessageBox("stopped...");
return
0;
}
}
}
}
if
(i==j)
{
AfxMessageBox("There is no such HID device...");
}
return
0;
为了不影响主线程的运行,我把读取数据的操作,放在一个子线程里!每隔50ms去读取一次数据!
首先创建一个线程:
在线程的程序里:
第三步:向HID设备写数据(根据用户提供的HID的vendorID和productID),用户输入的是二进制数据:
与读的程序一样,唯一区别就是红色那部分!
UpdateData(true);
bStopHID=false;
CString temp;
CString DevicePath;
temp="";
int Count = 0; //Total number of devices found
DWORD strSize=0,requiredSize=0;
BOOL result1,result2;
ULONG DeviceInterfaceDetailDataSize;
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData;
//PSP_DEVICE_INTERFACE_DETAIL_DATA test;
//1
GUID deviceId;
HidD_GetHidGuid(&deviceId);
int venderID=v_eVendorID;
int productID=v_eProductID;
unsigned char inbuffer[2];
unsigned long numBytesReturned;
HIDD_ATTRIBUTES devAttr;
PHIDP_PREPARSED_DATA PreparsedData;
HIDP_CAPS Capabilities;
int readValue;
bool LED;
int flag=0;
inbuffer[0]=0;
//把界面里的二进制转换成10进制
inbuffer[1]=m_eByte0*1+m_eByte1*2+m_eByte2*4+m_eByte3*8+m_eByte4*16+m_eByte5*32+m_eByte6*64+m_eByte7*128;
v_eDataToWrite=inbuffer[1];
UpdateData(false);
//2
HDEVINFO handle;
handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices
int i=0;
int j=m_ctllHIDdevices.GetCount();
for (i=0;i
{
m_ctllHIDdevices.GetText(i,temp);
DevicePath=temp;
HANDLE hCom = CreateFile
(
DevicePath,
GENERIC_READ
| GENERIC_WRITE,
FILE_SHARE_READ
| FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hCom ==
INVALID_HANDLE_VALUE)
{
//AfxMessageBox("Invalide
Device Path...");
continue;
}
devAttr.Size=sizeof(HIDD_ATTRIBUTES);
if
(!HidD_GetAttributes(hCom,&devAttr))
{
CloseHandle(hCom);
AfxMessageBox("Cannot get the
parameters of the HID...");
return;
}
//temp.Format("Vendor ID: %d,
Product ID:%d",devAttr.VendorID,devAttr.ProductID); //Compare with
the Vendor ID and Product ID from Nakamura-san
//AfxMessageBox(temp);
if
(!HidD_GetPreparsedData(hCom,&PreparsedData))
{
CloseHandle(hCom);
AfxMessageBox("Cannot get the
Preparsed Data...");
return;
}
if(!HidP_GetCaps(PreparsedData,&Capabilities))
{
CloseHandle(hCom);
AfxMessageBox("Cannot get the
Cap Data...");
return;
}
// Write File
if (devAttr.VendorID ==
venderID && devAttr.ProductID ==
productID)
{
result1 = WriteFile(hCom, inbuffer,
2, &numBytesReturned, NULL);
//temp=inbuffer;
//p->m_eDataRead=CString(inbuffer);
//p->UpdateData(false);
if(!result1)
{
AfxMessageBox("Cannot Write
Data...");
return;
}
AfxMessageBox("Suncess...");
break;
}
}
if (i==j)
{
AfxMessageBox("There is no such
HID device...");
}
return;
与读的程序一样,唯一区别就是红色那部分!
UpdateData(true);
bStopHID=false;
CString temp;
CString DevicePath;
temp="";
int Count = 0; //Total number of devices found
DWORD strSize=0,requiredSize=0;
BOOL result1,result2;
ULONG DeviceInterfaceDetailDat
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVICE_INTERFACE_DATA
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailDat
//PSP_DEVICE_INTERFACE_DETAIL_DATA test;
//1
GUID deviceId;
HidD_GetHidGuid(&deviceId);
int venderID=v_eVendorID;
int productID=v_eProductID;
unsigned char inbuffer[2];
unsigned long numBytesReturned;
HIDD_ATTRIBUTES devAttr;
PHIDP_PREPARSED_DATA PreparsedData;
HIDP_CAPS Capabilities;
int readValue;
bool LED;
int flag=0;
inbuffer[0]=0;
//把界面里的二进制转换成10进制
inbuffer[1]=m_eByte0*1+m_eByte1*2+m_eByte2*4+m_eByte3*8+m_eByte4*16+m_eByte5*32+m_eByte6*64+m_eByte7*128;
v_eDataToWrite=inbuffer[1];
UpdateData(false);
//2
HDEVINFO handle;
handle = SetupDiGetClassDevs(&deviceId, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); //Get only HID devices
int i=0;
int j=m_ctllHIDdevices.GetCount();
for (i=0;i
{
// Write File
}
if (i==j)
{
}
return;
后一篇:[转载]数据在网络上的传送过程