DSF USB HID Generic Sample
The DSF USB HID generic code sample shows how to build a basic USB HID device that conforms to the Device Simulation Framework (DSF). The code shows how to set up the simulated device to look like a HID device. You can also use the hclient sample to detect HID reports that the simulated hardware generates. Users can then verify that the simulated hardware generates a response. For more information about the hclient sample, see HClient. For information about the device stack for a HIDClass device, see Device Stacks for Generic HIDClass Devices.
Theory of Operation
Overview of the Simulator
The structure of the generic USB HID simulator sample is similar to the DSF USB Loopback Device Simulation sample. The generic USB HID simulator has the following structure:
An InProc COM object that implements a USB 1.1 HID device simulator. This object interacts with DSF COM objects to implement the interaction between the device simulator and the controller simulator.
A test script that creates an instance of the InProc COM object. The InProc COM object represents the simulated device. The test script plugs the simulated device into the controller while the controller is running.
The generic HID simulator creates the USB HID-specific device and report descriptors and returns them to the host as described in the USB HID Device Class specification. These device and report descriptors vary per device. Therefore, you must update the device and report descriptors in the sample code for your particular device. The generic HID sample only implements generic device-to-host requests. As a result, you must implement device class-specific requests that conform to the device class specifications. The HID generic sample does not include any host-to-device requests. In practice, however, you can implement host-to-device requests as determined by the device class specifications. To customize the HID generic sample to simulate a specific HID device class, you might have to update the CHIDDevice::OnDeviceRequest method according to specifications.
Initializing the Simulator
By default, the simulator is initialized by the class constructor (CHIDDevice::CHIDDevice) and the FinalConstruct method (CHIDDevice::FinalConstruct), respectively. The constructor initializes the global variables and FinalConstruct initializes the properties of the generic USB device. To initialize the properties of the generic HID device, FinalConstruct calls CHIDDevice::BuildHIDDescriptors. Then, the sample code populates the sample report descriptor in CHIDDevice::CreateReportDescriptor and the sample device descriptor in CHIDDevice::CreateHIDDescriptor. Alternatively, your code can use CHIDDevice::CreateCustomHIDDescriptor and CHIDDevice::CreateCustomReportDescriptor and can pass in the SAFEARRAY that contains the custom descriptors to create a custom HID device. Finally, the sample code calls CHIDDevice::ConfigureDevice to create and initialize USB device endpoints, interfaces, and configurations. As part of the device configuration process, the sample code configures the event sink for the control endpoint in CHIDDevice::SetupControlConnectionPoint. For your simulation, your code can add event sinks for the IN endpoint and any other endpoints.
Endpoint Data Transfers
The HID generic sample implements only an interrupt IN endpoint that you can customize in CHIDDevice::ConfigureINEndpoint. For example, you can modify m_piINEndpoint->put_Attributes to implement a bulk transfer endpoint instead of an interrupt transfer endpoint. Your HID simulated device should use event-driven processing for interrupt transfers. To use the IN endpoint in this simulation, queue in SAFEARRAY inputs to CHIDDevice::QueueInputReport that contain the HID input reports for the device. Input reports are structured according to the HID device that is implemented. Use CHIDDevice::StartProcessing and CHIDDevice::StopProcessing to start and stop processing the data that is queued into the IN endpoint. The CHIDDevice::get_IdleTimeout and CHIDDevice::put_IdleTimeout methods allow the user to get or set the rate at which the device endpoint handles each input report.
Other Simulator Methods and Properties
The simulator requires a property that exposes the object that is returned by the SoftUSBDevice.DSFDevice method. SoftUSBDevice.DSFDevice is implemented in CHIDDevice::get_DSFDevice. The CHIDDevice::CreateStrings method provides the utility to add strings that are used by the device simulator.
Terminating the Simulator
The SoftUSBDevice.Destroy method removes the event sinks and releases all objects. The simulator implements this method in CHIDDevice::Destroy. Also, you should perform resource cleanup in CHIDDevice::Destroy.
All of the preceding information does not address the myriad error conditions that could occur during all phases of operation. You must take these error conditions into account and implement them according to the USB and USBHID specifications. In the HID generic sample COM object, the Logging property and SetEndpointDiagnostics method are provided for debugging purposes. The CHIDDevice::SetEndpointDiagnostics method sets the level of debug output on the endpoints that can be viewed from the kernel debugger. The CHIDDevice::put_Logging method turns on or off the debug output that the simulator generates.
Stats and Diagnostics
If your test applications must monitor diagnostic information about the simulated device, you can implement this monitoring by collecting the information in CHIDDevice and exposing the information through the properties that are set on the CHIDDevice object. For example, to track the total amount of bytes that are read and written, CHIDDevice could keep member variables for each of these running totals. To provide access to test applications, the simulated device could expose TotalRead and TotalWritten properties on the COM object that simply return the current values of the member variables. Be aware that access to those variables would have to be synchronized.
Building the Sample
You can find the sample code for the HID generic device in the src\test\dsf\usb\GenericHID directory. To build a custom version of the device simulator, use the WDK build environment and run build -cZP. This command generates a COM library called SoftHIDReceiver.dll. Alternatively, this resource is provided and ready to use when the DSF runtime is installed.
You can also build this sample by using Microsoft Visual Studio 2005 or later versions of Visual Studio.
Generic HID Device Simulation Walkthrough
The following steps show the flow of a sample test scenario:
Install the DSF runtime by using either DSFx86Runtime.msi or DSFx64Runtime.msi.
Run %programfiles%\dsf\softehcicfg.exe /install to create a simulated USB 2.0 EHCI controller and to simulate plugging the controller into the host system.
Run cscript.exe TestGenericHID.wsf.
- Create a DSF.DSF COM object to provide access to the helper methods that DSF exposes.
- Create a SOFTUSB.SoftUSBHub COM object to create a USB hub simulation. This simulation is needed to plug in a USB 1.1 device.
- To expose the controller's root hub ports, look up the simulated controller from the collection of DSF devices. Use the root hub ports to locate a port to plug in the simulated hub and wait for the device to enumerate.
- Create the SoftHIDReceiver.HIDDevice.1 COM object that represents the generic HID device simulation. The test will then turn on logging.
- Call, in order, CHIDDevice::CreateCustomReportDescriptor, CHIDDevice::CreateCustomHIDDescriptor, and CHIDDevice::ConfigureDevice to perform the device initialization.
- Locate an available port on the USB hub and plug the hub into the controller while the controller is running. Wait for the device to enumerate.
- Next, create input reports, queue them to the endpoint, and start processing the reports. When I/O testing is complete, stop processing.
- When testing is complete, call the unplug method on the hub to remove the generic HID device.
- Call the unplug method on the root hub to remove the hub from the controller.
- Call the CHIDDevice::Destroy method to clean up any remaining resources.
Run softehcicfg /remove to unplug the controller from the host.
Build date: 9/21/2010