USB HID and C Sharp



It is easy to transfer data between an USB HID device and a Windows PC using AHid.dll. By means of a sample project, we demonstrate the steps to be taken.

Figure 1 shows the graphical user interface (GUI). Three buttons allow the connection to the HID device, sending data and to reset the counters and the list box control.

The GUI is divided into three parts. The Device section holds values to be used with Input and Output transfers as well. These values include the VID (Vendor ID), the PID (Product ID), the Interface ID and the GUID of the HID device.

The Vendor ID, Product ID and the Data edit boxes are filled with hexadecimal numbers. All others are decimal numbers. The Interface ID corresponds to the interface of a HID composite device. Set it to -1 if your device has no interfaces defined (as is often the case).

Figure 1: GUI to send and receive data using AHid.dll.

The Output section shows values corresponding to the Output Report. The Report ID is set to zero and the size is 32. A value of zero for the Report ID is used if the Report Descriptor does not define an ID at all.

The Input section defines the values corresponding to the Input Report. All numbers herein are also taken from the Report Descriptor of the HID device.

The Report Descriptor is part of the device firmware. Ask your hardware developer for additional information.


The implementation can be divided into five parts:

1. Initialization of the DLL using AHid_init().
2. Creation of transfer handles using AHid_register().
3. Reading from the HID device using AHid_read().
4. Writing to the HID device using AHid_write().
5. Tracking the device state using AHid_find().

The very first step to take is to initialize AHid.dll by a call to AHid_init() (not shown here, compare to the source code).

Then, the pipe handles are created in the connect() function using AHid_register() (figure 2). These handles identify the data pipes to be used for Input and Output transfers. They are passed as parameters to all AHid.dll functions.

The AHid_deregister() function removes these pipes again on termination of the application.

Figure 2: Initialization and registration of the pipe handle.

After the registration of the pipe handles with AHid_register(), data transfers can take place. AHid_write() is used to send data to the HID device inside the write() function (figure 3).

Note that AHid_write() can only send data of a fixed size. This size is equal to the Report Size parameter used earlier in the AHid_register() function.

The data itself is taken from the Data edit control placed in the graphical user interface. You have to extract and convert it before you can send it to the HID device.

Figure 3: Read and write data from/to the HID device.

Data reception is done by AHid_read(). The function is part of read() that is called inside a timer callback.

Note that AHid_read() can only read data of a fixed size. This size is equal to the Report Size parameter used earlier in the AHid_register() function.

A major factor in this context is to read at least the maximum amount of data packets that could be in theory be received. USB low or full speed HID devices are able to transfer one data packet per millisecond. So, if the timer interval is 100 ms, you must do 100 calls to AHid_read(). In case of an interval of 10 ms, 10 calls must be done.

There is no reason to fear a loss of data. AHid.dll is caching all data receeived from the HID device until AHid_read() is called.

The sample project is using a timer interval of 100 ms.

Figure 4: Track the connection state and read the GUID.

USB devices can be plugged and unplugged from the USB and it may be helpful to know the current connection state. The best choice for this task is AHid_find(). AHid_find() is called inside the find() function which is called from another timer interrupt (figure 4).

AHid_find() is not time critical (similar to AHid_read()). Its calling interval can be reduced to one second.

All pipe handles of a HID device do have the same GUID. Pipe handles of different HID devices do have different GUIDs. And if you use multiple HID devices with AHid.dll at the same time, you can use the AHid_identify() function to read the GUID of each pipe.

Because Pipe handles with the same GUID are part of the same HID device, you can use the GUID to group all pipe handles of each individual HID device together. If you just use a single HID device, AHid_identify() is needless.

Reading the GUID with AHid_identify() is also done inside the find() function.