Skip to content

Commit

Permalink
DRYs up usb enumeration code
Browse files Browse the repository at this point in the history
  • Loading branch information
TheNotary committed Sep 14, 2024
1 parent 3b3d1bf commit f8f0acd
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 85 deletions.
33 changes: 33 additions & 0 deletions include/main/usb_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,51 @@ void PrintMessagesInBuffer(const unsigned char* buffer, size_t message_count, si
// Private...
void PrintMessageInBuffer(const unsigned char* buffer, size_t i, size_t message_length);

/**
* Searches for a USB device with a matching vid, pid combination.
*
* @param vid The Vendor ID of the device to filter for
* @param pid The Product ID of the device to filter for
* @param target_device_path A c-string representing the device path that should be interfaced with
* @return HANDLE
*/
HANDLE SearchForDevice(short vid, short pid, const char* target_device_path);

/**
* Sends a buffer to a USB device. This function will only issue a SetReport message for each packet sent.
*
* @param deviceHandle The handle to the device to send the messages to
* @param messages_ptr The message data to send
* @param messageCount The number of messages to send as a packet
* @param messageLength The size in bytes of each packet
* @return HANDLE
*/
void SendBufferToDevice(
HANDLE deviceHandle, const unsigned char* messages_ptr,
size_t messageCount, size_t messageLength
);

/**
* Sends a buffer to a USB device. This function will issue both a SetReport and GetReport for each packet sent.
*
* @param deviceHandle The handle to the device to send the messages to
* @param messages_ptr The message data to send
* @param messageCount The number of messages to send as a packet
* @param messageLength The size in bytes of each packet
* @return HANDLE
*/
void SendBufferToDeviceAndGetResp(
HANDLE deviceHandle, const unsigned char* messages,
size_t messageCount, size_t messageLength
);

/**
* Lists available USB devices currently attached to the machine. Available devices are listed in
* the known_keyboards array.
*
* @return std::vector<KeyboardInfo> A list of available, currently connected keyboards
*/
std::vector<KeyboardInfo> ListAvailableKeyboards();


}
138 changes: 53 additions & 85 deletions src/blink/usb_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,23 @@ void DoAdditionalUsbThings(HANDLE hDev) {
HidD_FreePreparsedData(preparsedData);
}

HANDLE SearchForDevice(short vid, short pid, const char* target_device_path) {
/*
* This functions can be passed a lambda allowing really clean re-use of the C++ logic!
* Return false from the caller's lambda to halt the enumeration and clean up the USB
* stuff without closing the last handle.
*
* Return true from the lambda to close the handle and continue enumerating until all devices have been enumerated.
**/
template <typename DeviceHandler>
void EnumerateDevices(DeviceHandler handleDevice) {
GUID hidGuid;
HidD_GetHidGuid(&hidGuid);

HDEVINFO deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);

if (deviceInfoList == INVALID_HANDLE_VALUE)
return 0;
return;

const size_t DEVICE_DETAILS_SIZE = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH;
DWORD size = DEVICE_DETAILS_SIZE;
Expand All @@ -153,126 +161,86 @@ HANDLE SearchForDevice(short vid, short pid, const char* target_device_path) {
HIDD_ATTRIBUTES deviceAttributes;
deviceAttributes.Size = sizeof(deviceAttributes);

// This is the handle to the USB device that is used for communicating with it

for (int i = 0; ; ++i) {
HANDLE hDev = INVALID_HANDLE_VALUE;

if (!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo))
if (!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo)) {
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
else
continue;
}

if (!SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo,
deviceDetails, size, &size, &device_info_data)
)
deviceDetails, size, &size, &device_info_data)) {
continue;
}

hDev = open_device(deviceDetails->DevicePath);
if (hDev == INVALID_HANDLE_VALUE) {
// printf("Failed creating file");
continue;
}

// DoAdditionalUsbThings(hDev);

if (!HidD_GetAttributes(hDev, &deviceAttributes)) {
printf("Failed calling HidD_GetAttributes");
CloseHandle(hDev);
continue;
}

//PrintDeviceDetails(hDev, deviceDetails, deviceInfo, device_info_data, deviceAttributes);
// PrintDeviceDetails(hDev, deviceDetails, deviceInfo, device_info_data, deviceAttributes);

if (deviceAttributes.VendorID == vid && deviceAttributes.ProductID == pid) {
bool yield_result = handleDevice(hDev, deviceDetails, deviceAttributes, deviceInfo, device_info_data);

if (strstr(deviceDetails->DevicePath, target_device_path)) {
//PrintDeviceDetails(hDev, deviceDetails, deviceInfo, device_info_data, deviceAttributes);

SetupDiDestroyDeviceInfoList(deviceInfoList);
return hDev;
}
if (!yield_result) {
break;
}
CloseHandle(hDev);
}

SetupDiDestroyDeviceInfoList(deviceInfoList);
return 0;
}

// TODO: DRY this function up against SearchForDevice?
HANDLE SearchForDevice(short vid, short pid, const char* target_device_path) {
HANDLE resultHandle = 0;

EnumerateDevices([&](HANDLE hDev, SP_DEVICE_INTERFACE_DETAIL_DATA* deviceDetails,
HIDD_ATTRIBUTES& deviceAttributes,
SP_DEVICE_INTERFACE_DATA& deviceInfo, SP_DEVINFO_DATA& device_info_data) -> bool {
if (deviceAttributes.VendorID == vid && deviceAttributes.ProductID == pid) {
if (strstr(deviceDetails->DevicePath, target_device_path)) {
resultHandle = hDev;
return false;
}
}
return true;
}
);

return resultHandle;
}

/*
* Returns a list of keyboards that are attached to the system and are known to the program per known_keyboards.h
*/
std::vector<KeyboardInfo> ListAvailableKeyboards() {
std::vector<KeyboardInfo> available_keyboards;

GUID hidGuid;
HidD_GetHidGuid(&hidGuid);

HDEVINFO deviceInfoList;
deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);

if (deviceInfoList == INVALID_HANDLE_VALUE)
return available_keyboards;

const size_t DEVICE_DETAILS_SIZE = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH;
DWORD size = DEVICE_DETAILS_SIZE;
SP_DEVICE_INTERFACE_DETAIL_DATA* deviceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA*)alloca(DEVICE_DETAILS_SIZE);
deviceDetails->cbSize = sizeof(*deviceDetails);

SP_DEVICE_INTERFACE_DATA deviceInfo;
deviceInfo.cbSize = sizeof(deviceInfo);

SP_DEVINFO_DATA device_info_data;
device_info_data.cbSize = sizeof(device_info_data);

HIDD_ATTRIBUTES deviceAttributes;
deviceAttributes.Size = sizeof(deviceAttributes);

for (int i = 0; ; ++i) {
HANDLE hDev = INVALID_HANDLE_VALUE;

if (!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo))
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
else
continue;

if (!SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo,
deviceDetails, size, &size, &device_info_data))
continue;

hDev = open_device(deviceDetails->DevicePath);
if (hDev == INVALID_HANDLE_VALUE) {
// printf("Failed creating file");
continue;
}

if (!HidD_GetAttributes(hDev, &deviceAttributes)) {
printf("Failed calling HidD_GetAttributes");
continue;
}

// PrintDeviceDetails(hDev, deviceDetails, deviceInfo, device_info_data, deviceAttributes);

CloseHandle(hDev);

for (size_t i = 0; i < known_keyboards.size(); i++) {
KeyboardInfo known_keyboard = known_keyboards[i];
if (deviceAttributes.VendorID == known_keyboard.vid && deviceAttributes.ProductID == known_keyboard.pid) {

// If we already have this keyboard listed in the available_keyboards vector, skip
if ( std::find(available_keyboards.begin(), available_keyboards.end(), known_keyboard) != available_keyboards.end() )
continue;

available_keyboards.push_back(known_keyboard);
continue;
EnumerateDevices([&](HANDLE hDev, SP_DEVICE_INTERFACE_DETAIL_DATA* deviceDetails,
HIDD_ATTRIBUTES& deviceAttributes,
SP_DEVICE_INTERFACE_DATA& deviceInfo, SP_DEVINFO_DATA& device_info_data) -> bool {
for (size_t i = 0; i < known_keyboards.size(); i++) {
KeyboardInfo known_keyboard = known_keyboards[i];
if (deviceAttributes.VendorID == known_keyboard.vid && deviceAttributes.ProductID == known_keyboard.pid) {
// If we haven't already added this keyboard to available_keyboards, do so
if (std::find(available_keyboards.begin(), available_keyboards.end(), known_keyboard) == available_keyboards.end()) {
available_keyboards.push_back(known_keyboard);
return true;
}
}
}
return true;
}
}
SetupDiDestroyDeviceInfoList(deviceInfoList);
);

return available_keyboards;
}

Expand Down

0 comments on commit f8f0acd

Please sign in to comment.