Get HID report Descriptor from .pcap file - c++

I am building a C++ app on windows that should reinterpret USB data stream captured by Wireshark and USBPCap stored into a .pcap file. I am currently having trouble to get HID Report descriptor, so then i would be able to interpret data that mouse sends to the host.
The site USB Made Simple has been a great source of information so far, and i have also read a tons of tutorials how to write your own HID Report descriptor in order to understand them. But what i need is to retrieve one from current data flow.
According to wireshark, mouse is sending me a DEVICE DESCRIPTOR (example here), after that it sends CONFIGURATION DESCRIPTOR with its INTERFACE, HID and ENDPOINT DESCRIPTORS (example here).
According to value of wDescriptorLength in HID DESCRIPTOR, there should be HID REPORT DESCRIPTOR of length 56, but there is not. After this there is only ENDPOINT DESCRIPTOR of length 7 and another INTERFACE and HID DESCRIPTOR of total lenght 18.
Is there any way to get HID REPORT DESCRIPTOR from this or am I missing something out ?
Thank you for any input.

Is there any way to get HID REPORT DESCRIPTOR from this or am I missing something out ?
Don't know about you but for me that looks like Wireshark/USBPCap is missing something.
If you compare it with mine example it looks like entries with USBHID protocol are missing in your part.
Please check your Wireshark version or if you don't have enabled any filters in capture configuration.
If you click 'gear' icon on the left side of USBPcap interface you can check your current settings:
Important note:
Despite fact that "Inject already connected devices descriptors..." is checked it doesn't work for me like I would expect and to capture Report Descriptor you have to reconnect device: unplug USB-HID device -> Start capture -> Plug in USB device -> Now you can stop capture.

You should be able to use the Win32 HID-parse utilities to do this:
https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/preparsed-data
See here for an example of use, where the HID report is accessed using WM_INPUT:
https://github.com/supersmo/Using-Raw-Input-API-to-Process-Joystick-Input
...in particular these methods:
// determine buffer size required
CHECK( GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize) == 0 );
// allocate buffer
CHECK( pPreparsedData = (PHIDP_PREPARSED_DATA)HeapAlloc(hHeap, 0, bufferSize) );
// determine the usages etc
CHECK( (int)GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, pPreparsedData, &bufferSize) >= 0 );
// Button caps
CHECK( HidP_GetCaps(pPreparsedData, &Caps) == HIDP_STATUS_SUCCESS )
// Value caps
CHECK( pValueCaps = (PHIDP_VALUE_CAPS)HeapAlloc(hHeap, 0, sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps) );
capsLength = Caps.NumberInputValueCaps;
CHECK( HidP_GetValueCaps(HidP_Input, pValueCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS )
Another thing to look at is the ReactOS hidusb source which can be found (today) here:
https://doxygen.reactos.org/dd/d06/hidusb_8c_source.html
...pay particular attention to e.g. HidUsb_GetReportDescriptor
Hope this points you in the right direction.

Related

Using HidD_GetInputReport(..) to retrive XBOX ONEs button states

I am trying to talk to the XBOX ONE Controller via the Microsoft HID API without using XINPUT. I'm currently able to control all the rumble motors (including the force feedback triggers) by sending the packet using HidD_SetOutputReport(HANDLE, VOID*, ULONG). But I'm stuck reading the button values using HidD_GetInputReport(HANDLE, VOID*, ULONG) or ReadFile() / ReadFileEx() with and without the HANDLE being created with FILE_FLAG_OVERLAPPED and using OVERLAPPED and Windows Events.
I have already reverse engineered the USB URB protocol with the help of the following article https://github.com/quantus/xbox-one-controller-protocol. The main goal is to overcome the XINPUT overhead and writing a flexible framework so that I can integrate other gamepads as well.
That is what I accomplished:
I have connected the gamepad via USB with my computer (So that I can read all the USB Packages sent and received from the device)
I have found the controller’s path using SetupDiGetClassDevs(...), SetupDiEnumDeviceInfo(...), SetupDiEnumDeviceInterfaces(...) and SetupDiGetDeviceInterfaceDetail(...)
I have created a handle to the device using HANDLE gamePad = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL)
Using HidP_GetCaps(HANDLE, HIDP_CAPS*) doesn’t seem to return valid data since it reports a OutputReportByteLength of 0 but I am able to send Output reports of size 5 (Turn ON) and 9 (Set rumble motors)
All in and outcoming data (At least buttons and Rumble motors) seem to follow the following pattern
byte 0: Package type
byte 1: was always 0x00
byte 2: Package number (always incrementing every package)
byte 3: Size of following data
byte 4+: <Data>
With that information i was able to let the motors and triggers rumble as I desire
For example: Two of my output rumble packets look like this (Using the pulse length to dirty turn on and off the motors):
This turns on and of all motors with the rumble motors speed at 0xFF and the triggers at speed 0xF0. This is how I did it:
struct RumbleContinous{
BYTE mode;
BYTE mask; // Motor Mask 0b 0 0 0 0 LT RT L R
BYTE lTForce;
BYTE rTForce;
BYTE lForce;
BYTE rForce;
BYTE pulseLength;
BYTE offTime;
BYTE terminator; // Terminator / Dummy / ?? (XINPUT sends that as 0xEB!) / Changing seems to not make any changes
};
RumbleContinous rc = {0x00, 0x0F, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF 0x00, 0xEB};
HidD_SetOutputReport(gamePad, (PVOID)&rc, sizeof(RumbleContinous ));
Now to my problem
Looking at the input packages from the controller it looks like you need to create a buffer of size 0x0E = 14, ZeroMemory it (or just write the first byte to 0 like MSDN is suggesting) and just call HidD_GetInputReport(HANDLE, buffer, 14)
So what I did was calling HidD_FlushQueue() to make sure the next package is the input package. Then I insert a little delay so that I am able to change some controller values. After that I tried reading into a BYTE array with HidD_GetInputReport(HANDLE, cmd_in, 14) but the function always failed with GetLastError() == 0x00000057 // ERROR_INVALID_PARAMETER
Since HID is able to filter packages it may be required to allocate a buffer one byte larger than expected and pass the required report id to the buffer at location 0. This is what I did:
BYTE cmd_in[15];
ZeroMemory(cmd_in, 15);
cmd_in[0] = 0x20;
HidD_GetInputReport(gamePad, cmd_in, 15);
Still no success. Since the HidP_GetCaps(...) function reported an input report of 16 (But I don't trust this since it already fooled me with output report size of 0) I tried sweeping over many buffer sizes:
BYTE cmd_in[30];
for (UINT bs = 0; bs < 30; bs++) {
ZeroMemory(cmd_in, 30);
HidD_FlushQueue(gamePad); // Flushing works
Sleep(500);
if (HidD_GetInputReport(gamePad, cmd_in, bs)) {
// Output result (ommited)
}
else {
// Print error (ommited)
}
}
and
BYTE cmd_in[30];
for (UINT bs = 0; bs < 30; bs++) {
ZeroMemory(cmd_in, 30);
cmd_in[0] = 0x20;
HidD_FlushQueue(gamePad); // Flushing works
Sleep(500);
if (HidD_GetInputReport(gamePad, cmd_in, bs)) {
// Output result (ommited)
}
else {
// Print error (ommited)
}
}
Still no success. According to the special required output format and the wrong HidP_GetCaps(...) readings i suspect that the XBOX ONE Gamepad Driver requires a special header already beeing in the input buffer (As far as I know HidD_GetInputReport(...) just calls the User / Kernel Mode Driver call back; So the driver is free to perform checks and reject all data being send to it)
Maybe anyone out there does know how to call HidD_GetInputReport(...) for the XBOX One controller
I know that it is possible to retrieve that input data since the SimpleHIDWrite is able to see the button states. Even through the format is totally different (The two triggers for example are combined in one byte. In the USB Packed each trigger has its own byte):
I should also mention that the HIDWrite sees the data without the press of any button! Looking at the log from the SimpleHIDWrite it looked like it is reading RD from 00 15 bytes of data, having a 16-byte array and element 0 at 00 (Didn't work in my application). Or does it just dump all data coming in. If yes how is this possible? That would be an option for me too!
I looked at what XINPUT is doing when executing the following code:
XINPUT_STATE s;
XInputGetState(0, &s);
It turned out that XINPUT is doing the same stuff I did until it comes to reading the data from the controler. Insteal of HidD_GetInputReport(...) XINPUT is calling DeviceIoControl(...). So what I did was a fast google serch "DeviceIoControl xbox" and tada here it is without the need to to figure out the memory layout on my own: Getting xbox controller input without xinput
Edit: Using DeviceIoControl(...) works even if the gamepad is connected via bluetooth while HidD_SetOutputReport(...) does not work when the gamepad is connected via bluetooth. I rember reading something that DeviceIoControl(...) via bluetooth requires an addition parameter to be present in the output buffer. But I'm currently trying to figure out a way to controle the rumble motors via DeviceIoControl(...). If you have any sugestions feel free to comment! The article in the link above only activates the two rumble motors but not the triggers!
Edit 2: I tried sweeping over DeviceIoControl(HANDLE, j, CHAR*, i, NULL, 0, DWORD*, NULL) from j 0x0 to 0xFFFFFFFF and i 0x1 to 0x3F. Well it worked... at first... but after a few values of j I got a Blue-Screen: WDF_Violation (At least I know how to crash a computer ;) )

How to track screens through time? [duplicate]

I have a setup with two regular displays and three projectors connected to a windows pc. In my win32 program I need to uniquely identify each monitor and store information for each such that I can retrieve the stored information even after computer restart.
The EnumDisplayDevices seems to return different device orders after restarting the computer. There is also GetPhysicalMonitorsFromHMONITOR which at least gives me the display's name. However, I need something like a serial number for my projectors, since they are the same model. How can I get such a unique identifier?
EDIT: This is the solution I came up with after reading the answer from user Anders (thanks!):
DISPLAY_DEVICEA dispDevice;
ZeroMemory(&dispDevice, sizeof(dispDevice));
dispDevice.cb = sizeof(dispDevice);
DWORD screenID;
while (EnumDisplayDevicesA(NULL, screenID, &dispDevice, 0))
{
// important: make copy of DeviceName
char name[sizeof(dispDevice.DeviceName)];
strcpy(name, dispDevice.DeviceName);
if (EnumDisplayDevicesA(name, 0, &dispDevice, EDD_GET_DEVICE_INTERFACE_NAME))
{
// at this point dispDevice.DeviceID contains a unique identifier for the monitor
}
++screenID;
}
EnumDisplayDevices with the EDD_GET_DEVICE_INTERFACE_NAME flag should give you a usable string. And if not, you can use this string with the SetupAPI to get the hardware id or driver key or whatever is unique enough for your purpose.
Set this flag to EDD_GET_DEVICE_INTERFACE_NAME (0x00000001) to retrieve the device interface name for GUID_DEVINTERFACE_MONITOR, which is registered by the operating system on a per monitor basis. The value is placed in the DeviceID member of the DISPLAY_DEVICE structure returned in lpDisplayDevice. The resulting device interface name can be used with SetupAPI functions and serves as a link between GDI monitor devices and SetupAPI monitor devices.

windows: detect same device on both bluetooth api and setupapi

I'm currently creating a program that's divided in two parts, one where I detect nearby bluetooth devices and connect them to the pc if the name match and the other where I search for the device with setupapi and get an handle for HID comunication.
My problem is that I cannot find anything that tells me that the device I just connected is the same I found in setupapi.
So in the first part I have something like this:
BLUETOOTH_DEVICE_INFO btdi;
//--- Code omitted ---
BluetoothGetDeviceInfo(radio_handle, &btdi);
if(std::wstring(btdi.szName) == /*my name*/)
// Device found! now connect
BluetoothSetServiceState(radio_handle, &btdi, &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE);
And the setupapi related code:
SP_DEVICE_INTERFACE_DATA device_data;
device_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
//--- Code omitted ---
SetupDiEnumDeviceInterfaces(device_infos, NULL, &hid_guid, index, &device_data);
I was thinking about using the bluetooth address of the device but there seem to be no way to get that from setupapi.
So, to recap, is there any way to get the address of the device from setupi? And, if not, is there any other way to be sure that they're both the same device?
Here I posted the code how to find Wiimote connected as HID using its MAC. You have to rework that code so it can use your HID device (change VID and PID).

Get unique identifier for Windows monitors

I have a setup with two regular displays and three projectors connected to a windows pc. In my win32 program I need to uniquely identify each monitor and store information for each such that I can retrieve the stored information even after computer restart.
The EnumDisplayDevices seems to return different device orders after restarting the computer. There is also GetPhysicalMonitorsFromHMONITOR which at least gives me the display's name. However, I need something like a serial number for my projectors, since they are the same model. How can I get such a unique identifier?
EDIT: This is the solution I came up with after reading the answer from user Anders (thanks!):
DISPLAY_DEVICEA dispDevice;
ZeroMemory(&dispDevice, sizeof(dispDevice));
dispDevice.cb = sizeof(dispDevice);
DWORD screenID;
while (EnumDisplayDevicesA(NULL, screenID, &dispDevice, 0))
{
// important: make copy of DeviceName
char name[sizeof(dispDevice.DeviceName)];
strcpy(name, dispDevice.DeviceName);
if (EnumDisplayDevicesA(name, 0, &dispDevice, EDD_GET_DEVICE_INTERFACE_NAME))
{
// at this point dispDevice.DeviceID contains a unique identifier for the monitor
}
++screenID;
}
EnumDisplayDevices with the EDD_GET_DEVICE_INTERFACE_NAME flag should give you a usable string. And if not, you can use this string with the SetupAPI to get the hardware id or driver key or whatever is unique enough for your purpose.
Set this flag to EDD_GET_DEVICE_INTERFACE_NAME (0x00000001) to retrieve the device interface name for GUID_DEVINTERFACE_MONITOR, which is registered by the operating system on a per monitor basis. The value is placed in the DeviceID member of the DISPLAY_DEVICE structure returned in lpDisplayDevice. The resulting device interface name can be used with SetupAPI functions and serves as a link between GDI monitor devices and SetupAPI monitor devices.

How to enumerate an USB hub that is attached to the first port of root hub on Windows Embedded 7

I am posting here for the first time, I hope this will be clear and readable.
I am currently trying to test the presence of usb devices on an embedded system using a specific HCD and port path programmatically using C++ and Visual Studio 2008.
The idea is to pass in the port number and the hcd value as the parameters of the function, and the function will return a true or false that indicates the connection status.
I have written some code to populate the root hub and prove that the device attached to port 1 of the root hub is a hub using bool DeviceIsHub from usbioctl.h.
However, when I attempt to enumerate the usb hub attached to port 1 of root so that I may test for the connection status of the downstream ports for the presence of device(ports 1 and 2 of this usb hub). It does not seem to know how many downstream ports the usb hub has.
I checked USBVIEW/TreeView, both application tells me that devices are there
but I am not sure what ioctl command code to use such that I can enumerate the downstream ports so I can check the connection status.
The structure of the device based on USB view and USB tree provides the following.
Root hub - it has 7 ports, only the first port is being used.
A USB hub (it has four available ports) is attached to the first port of the root hub.
Two USB devices (USB mouse and USB keyboard) are attached to port 1 and port 2 of the USB hub.
I have tried IOCTL_USB_GET_CONNECTION_INFORMATION, IOCTL_USB_GET_CONNECTION_NAME,
IOCTL_USB_GET_CONNECTION_INFORMATION_EX, IOCTL_USB_PORT_CONNECTOR_PROPERTIES
(which is not supported, it can only be used in windows 8, this is the exact ioctl call they used to enumerate the ports).
Please ignore the MessageBoxes, those are for me to check the control path status and determine which route it was following.
Please find the code that I wrote as I attempt to enumerate/populate the usb hub. I did not include the Root hub code because it would make this snippet too big.
My questions mainly resides in the enumeration process of the secondary USB hub I believe.
I just checked the registry key of the device. it appears that the USB hub is enumerated and present on the device since the information is shown under regedit HKLM->System->CurrentControlSet->Enum->USB. I believe I am not enumerating it correctly within my test application.
Any help would be greatly appreciated.
Update
The part that I am most concerned about is the DeviceIoControl Calls that attempts to get the size and the actual name of that USB hub.
It currently only takes in USB_GET_NODE_INFORMATION. Any other ioctl calls that are intended to retrieve the name of the hub will fail at the first DeviceIoControl where it attempts to get the size of the hub name so that it know how much memory to allocate
for it.
Update Part 2
From observing the usbview open source code, I believe I need to enumerate the host controller and all the devices first before checking for the presence of device. I drew a conclusion such that without doing the enumeration of controller, it only goes so far down the tree (at best second layer, which is where the external hub is attached to in my case).
I am currently attempting to enumerate the other devices and controllers in hope that I can get to the third layer of device. I will keep on updating this thread until either I figure out the problem myself or someone is capable of answering my questions.
//we are connected to the external hub, now we can begin the configuration and enumeration of the external hub.
ULONG kBytes = 0;
USB_HUB_NAME SubHubName;
//Create a Handle for the external hub driver
char Name[16];
wsprintf(Name, "\\\\.\\HCD%d", HcdSub);
HANDLE SubHub = CreateFile(Name,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
//Check to see if the handle was created successfully
if (SubHub == INVALID_HANDLE_VALUE)
{
MessageBox(NULL,"SubHandle Fail ","TEST",MB_OK);
return false;
}
//Query the SUBHUB/External Hub for the structure, this will tell us the number of down stream ports we need to enumerate
ioctlSuccess = DeviceIoControl(SubHub,
IOCTL_USB_GET_NODE_INFORMATION,
0,
0,
&SubHubName,
sizeof(SubHubName),
&kBytes,
NULL);
//If the command failed, close the handle and return false.
if(!ioctlSuccess)
{
CloseHandle(SubHub);
MessageBox(NULL," sub hub size fail ","TEST",MB_OK);
return false;
}
//Prepare to receive the SubHubName
kBytes = SubHubName.ActualLength;
USB_HUB_NAME *subHubNameW = (USB_HUB_NAME *) malloc(sizeof(USB_HUB_NAME) * kBytes);
//Check if the allocation failed, if it did, free the memory allocated and return false.
if (subHubNameW == NULL)
{
free(subHubNameW);
CloseHandle(SubHub);
MessageBox(NULL,"SUBHubNameW=NULL ","TEST",MB_OK);
return false;
}
//Send the command to retrieve the name
ioctlSuccess = DeviceIoControl(SubHub,
IOCTL_USB_GET_NODE_INFORMATION,
NULL,
0,
subHubNameW,
kBytes,
&kBytes,
NULL);
//We no longer need this handle.
CloseHandle(SubHub);
if(!ioctlSuccess)
{
if(subHubNameW !=NULL)
{
free(subHubNameW);
}
MessageBox(NULL,"GET NODE INFO FAIL ","TEST",MB_OK);
return false;
}
//Converts the SubHubNAme from widechar to a cahr.
MessageBox(NULL,"BEGIN CONVERTION","TEST",MB_OK);
kBytes = wcslen(subHubNameW->HubName) + 1;
char *subhubname = (char *) malloc(sizeof(char)*kBytes);
wcstombs(subhubname,subHubNameW->HubName, kBytes);
//we no longer need subHubNameW the information is now in subhubname.
if(subHubNameW !=NULL)
{
free(subHubNameW);
}
//Attempt to open a handle to driver for sub hub.
int SubhdnSize = strlen(subhubname) + sizeof("\\\\.\\");
char *subhubnamelength = (char *) malloc(sizeof(char) * SubhdnSize);
sprintf(subhubnamelength, "\\\\.\\%s", subhubname);
//We no longer need subhubname, so free it.
if(subhubname !=NULL) free(subhubname);
//Attempt to open a handle for enumerating ports on this hub.
HANDLE ExternalHub = CreateFile(subhubnamelength,
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
//we no longer need subhubnamelength, so free it if it is not NULL
if(subhubnamelength != NULL) free(subhubnamelength);
//Check and see if the handle was created successfully, if not, return false.
if(ExternalHub == INVALID_HANDLE_VALUE)
{
CloseHandle(ExternalHub);
MessageBox(NULL,"EXT handle fail ","TEST",MB_OK);
return false;
}
}
USB_NODE_CONNECTION_ATTRIBUTES *PortConnection =
(USB_NODE_CONNECTION_ATTRIBUTES *) malloc(sizeof(USB_NODE_CONNECTION_ATTRIBUTES));
PortConnection ->ConnectionIndex = Port;
ioctlSuccess = DeviceIoControl(ExternalHub,
IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES,
PortConnection,
sizeof(USB_NODE_CONNECTION_ATTRIBUTES),
PortConnection,
sizeof(USB_NODE_CONNECTION_ATTRIBUTES),
&kBytes,
NULL);
if(!ioctlSuccess)
{
MessageBox(NULL,"DEVICE CONNECTION FAIL ","TEST",MB_OK);
return false;
}
if(PortConnection->ConnectionStatus !=DeviceConnected)
{
printf("The Connection Status Returns: %d",PortConnection->ConnectionStatus);
printf("\n");
return false;
}
Enumerating USB on Windows 7 will fail if UAC is enabled and application doesn't have enough privilege. Windows Embedded 7 may fail also on similar task.
There is also a possibility to enumerate through registry.
You can not enumerate anything possibly. Normally the usb device is either a bus device or a child of a bus device. Sense the bus device is not removable, it is automatically enumerated by acpi.sys the root device during boot, or if a bus device for some other device attached to the root node, then that device has to undergo some event that means it detects the device and then enumerates it, plug and play will automatically look for it's device type's driver and if installed will load it. If the usb say has 4 actual usb connectors, that are controlled from a central device, there could be a usb driver/mini driver pair. In that case the miniport driver is a child of the usb driver and is enumerated by it and attached to it. The miniport's job is to know the actual hardware, and irp's and all other io will come from it's parent. If there are several physical connections there may be additional child drivers. They all operate the hardware and there is a hot plug. When the firmware detects the installation of a usb device it communicates this to the miniport driver and on down the stack to the bus and ultimately it is processed by plug and play. Plug and play will then have the miniport driver enumerate it's device, but it needs to get a hardware id. Then it can find it's driver and load that, then the device is installed and ready for operation.
With out knowing the device stack it is not clear what device it is referring to. Keep in mind the driver stack may not reflect the actual hardware topology. There are also things called logical devices which do not represent any piece of hardware. Any of these would have to be taken into account and you need to know which device corresponds to the end of the node.
Also one little detail. I'm not as familiar with user mode api's and drivers as I am kernel, but it seems wsprintf second argument controls format of the output buffer from the input. It should be %[]%[] were [] is a symbol that represents the format. It would format the first character according to the first symbol then the second character with teh second symbol. Seems you are doing something different.
A final note, it appears the use of wsprintf() is now deprecated instead for other api's.