This is an example of Microsoft C++ USB HID connection and control of the xArm 6-DOF robotic arm.
I created this as a little project to fully understand how to make a USB HID connection and communicate with the xArm in C++. I found plenty of examples but many were riddled with bad methods. This example demonstrates proper usage of the functions used to enumerate and communicate with USB HID devices. It simply reads the battery voltage.
output
Begin. HidGuid = {4D1E55B2-F16F-11CF-88CB-001111000030} hDevInfoSet Handle: 0070C5B8 Found at dwMemberIdx: 14 byteArrayBuffer (30): HID\VID_0483&PID_5750&REV_0201 DevicePath: \?\hid#vid_0483&pid_5750#7&35f6a2ad&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} WriteHandle: 00000284 Serial number: 497223563535 Manufacturer: MyUSB_HID Product: LOBOT Caps.OutputReportByteLength: 65 Caps.InputReportByteLength: 65 Voltage (mv): 7646 End.
test6.cpp
#include <windows.h>
#include <SetupAPI.h>
#include <hidsdi.h>
#include <string>
#include <iostream>
#pragma comment (lib, "Setupapi.lib")
#pragma comment (lib, "Hid.lib")
void PrintLastError();
void GetManufacturerString(HANDLE hHidDeviceObject);
void GetProductString(HANDLE hHidDeviceObject);
void GetBatteryVoltage(HANDLE hHidDeviceObject);
void GetSerialNumberString(HANDLE hHidDeviceObject);
// vendor_id=0x0483, product_id=0x5750
// Compile using Microsoft c++ command line compiler: cl /EHsc test6.cpp
int main(int argc, char *argv[]) {
printf("Begin.\n\n");
HDEVINFO hDevInfoSet;
SP_DEVINFO_DATA devInfoData;
SP_DEVICE_INTERFACE_DATA devIfcData;
PSP_DEVICE_INTERFACE_DETAIL_DATA devIfcDetailData;
HANDLE hHidDeviceObject;
DWORD dwMemberIdx = 0, dwSize, dwType;
GUID hidGuid;
PBYTE byteArrayBuffer;
std::string _vid = "0483";
std::string _pid = "5750";
std::string _serial_number = "497223563535";
wchar_t wString[127]; // For USB devices, maximum string length of 126 wchar plus terminating NULL character.
HidD_GetHidGuid(&hidGuid);
printf("HidGuid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}\n",
hidGuid.Data1, hidGuid.Data2, hidGuid.Data3,
hidGuid.Data4[0], hidGuid.Data4[1], hidGuid.Data4[2], hidGuid.Data4[3],
hidGuid.Data4[4], hidGuid.Data4[5], hidGuid.Data4[6], hidGuid.Data4[7]);
// Retrieve a list of all present USB devices with a device interface.
hDevInfoSet = SetupDiGetClassDevs(&hidGuid, NULL, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
printf("hDevInfoSet Handle: %lp\n", hDevInfoSet);
if (hDevInfoSet != INVALID_HANDLE_VALUE) {
while (true) {
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
// Get SP_DEVINFO_DATA for this member.
if (!SetupDiEnumDeviceInfo(hDevInfoSet, dwMemberIdx, &devInfoData)) {
break;
}
// Get required size for device property
SetupDiGetDeviceRegistryProperty(hDevInfoSet, &devInfoData, SPDRP_HARDWAREID, &dwType, NULL, 0, &dwSize);
// Allocate required memory for byteArrayBuffer to hold device property.
byteArrayBuffer = (PBYTE) malloc(dwSize * sizeof(BYTE));
// Get SPDRP_HARDWAREID device property
if (SetupDiGetDeviceRegistryProperty(hDevInfoSet, &devInfoData, SPDRP_HARDWAREID, &dwType, byteArrayBuffer, dwSize, NULL)) {
// VID and PID
std::string vid = "VID_" + _vid;
std::string pid = "PID_" + _pid;
// Test for VID/PID
if (strstr((char *)byteArrayBuffer, (char *)&pid) && strstr((char *)byteArrayBuffer, (char *)&vid)) {
printf("Found at dwMemberIdx: %i\n", dwMemberIdx);
printf("byteArrayBuffer (%i): %s\n", strlen((char *)byteArrayBuffer), byteArrayBuffer);
devIfcData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
SetupDiEnumDeviceInterfaces(hDevInfoSet, NULL, &hidGuid, dwMemberIdx, &devIfcData);
// Get required size for devIfcDetailData.
SetupDiGetDeviceInterfaceDetail(hDevInfoSet, &devIfcData, NULL, 0, &dwSize, NULL);
// Allocate required memory for devIfcDetailData.
devIfcDetailData = (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(dwSize);
devIfcDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// Get devIfcDetailData
SetupDiGetDeviceInterfaceDetail(hDevInfoSet, &devIfcData, devIfcDetailData, dwSize, &dwSize, NULL);
printf("DevicePath: %s\n", devIfcDetailData->DevicePath);
// Get Writehandle of device
hHidDeviceObject = CreateFile((devIfcDetailData->DevicePath), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
printf("WriteHandle: %lp\n", hHidDeviceObject);
GetSerialNumberString(hHidDeviceObject);
GetManufacturerString(hHidDeviceObject);
GetProductString(hHidDeviceObject);
GetBatteryVoltage(hHidDeviceObject);
CloseHandle(hHidDeviceObject);
// Release devIfcDetailData memory
free(devIfcDetailData);
}
}
// Release byteArrayBuffer memory
free(byteArrayBuffer);
dwMemberIdx++;
}
} else {
printf("devInfo == INVALID_HANDLE_VALUE\n");
}
SetupDiDestroyDeviceInfoList(hDevInfoSet);
printf("\nEnd.\n");
}
void PrintLastError() {
DWORD dwMessageId = GetLastError();
LPSTR lpBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwMessageId, 0, (LPSTR)&lpBuffer, 0, NULL);
printf("LastError: %s\n", lpBuffer);
LocalFree(lpBuffer);
}
void GetBatteryVoltage(HANDLE hHidDeviceObject) {
PHIDP_PREPARSED_DATA PreparsedData;
HIDP_CAPS Caps;
DWORD dwRead;
DWORD dwWritten;
HidD_GetPreparsedData(hHidDeviceObject, &PreparsedData);
HidP_GetCaps(PreparsedData, &Caps);
printf("Caps.OutputReportByteLength: %i\n", Caps.OutputReportByteLength);
printf("Caps.InputReportByteLength: %i\n", Caps.InputReportByteLength);
HidD_FreePreparsedData(PreparsedData);
PBYTE OutputReport = (PBYTE) malloc(Caps.OutputReportByteLength);
OutputReport[0] = 0x00; // Record #
OutputReport[1] = 0x55; // Header
OutputReport[2] = 0x55; // Header
OutputReport[3] = 0x02; // Len
OutputReport[4] = 0x0F; // Get battery voltage
WriteFile(hHidDeviceObject, OutputReport, Caps.OutputReportByteLength, &dwWritten, 0);
Sleep(500);
PBYTE InputReport = (PBYTE) malloc(Caps.InputReportByteLength);
ReadFile(hHidDeviceObject, InputReport, Caps.InputReportByteLength, &dwRead, 0);
int voltage = InputReport[6] * 256 + InputReport[5];
printf("Voltage (mv): %i\n", voltage);
free(InputReport);
free(OutputReport);
}
void GetManufacturerString(HANDLE hHidDeviceObject) {
PWCHAR Buffer = (PWCHAR) malloc(127);
if (HidD_GetManufacturerString(hHidDeviceObject, Buffer, 127)) {
printf("Manufacturer: %ws\n", Buffer);
} else {
PrintLastError();
}
free(Buffer);
}
void GetProductString(HANDLE hHidDeviceObject) {
PWCHAR Buffer = (PWCHAR) malloc(127);
if(HidD_GetProductString(hHidDeviceObject, Buffer, 127)) {
printf("Product: %ws\n", Buffer);
} else {
PrintLastError();
}
free(Buffer);
}
void GetSerialNumberString(HANDLE hHidDeviceObject) {
PWCHAR Buffer = (PWCHAR) malloc(127);
if(HidD_GetSerialNumberString(hHidDeviceObject, Buffer, 127)) {
printf("Serial number: %ws\n", Buffer);
} else {
PrintLastError();
}
free(Buffer);
}