KSL Embedded Blog
 

Working with USB HID Device in Java (Windows)

JNA library and WIN32 API

For communication with USB HID device in Windows, you can use JNA library. JNA provides Java programs easy access to native shared libraries (DLLs) without writing anything but Java code, no JNI or native code is required. For development we need only two files jna.jar (native accsess library) and platform.jar (platform specific package). Download library and platform package from java.net.

Microsoft Windows operation system provides three DDLs for work with USB HID device. See the diagram below, which explains the interrelation between Windows dynamic-link libraries and relevant functions defined in this DLLs. WIN32 API Diagram

Picture 1. WIN32 USB HID API diagram.

First of all we need to creat class member function that will find our HID device. Every USB device has unique ”Vendor Device IdentifierVID, ”Product Device IdentifierPID and Serial Number. Collection of these three parameters allows us to identify and select the desired device from the set of connected USB-devices. If you don't know device VID and PID go to the ”Control Panel→System→Hardware→Device Manager” and right click on the selected device. Choose ”Properties” tab in the popup menu. A new window will show Device Instance ID. Device Instance ID

Picture 2. Windows USB Device Instance ID.

Open USB HID Device

In our case device VID is ”534B” and PID is ”0012”. So, VID and PID we have identified. Now we need to get a handle to this device to be able open it using ”CreateFile” function. For this purpose we create ”getHIDHandle” function, which will help us find the right device. See the algorithm presented below, which explains the ”getHIDHandle” function workflow. getHIDHandle algorithm

Picture 3. Get USB HID device handle algorithm.

So, above you see a nice color figures with labels and arrows, but this beauty is not entirely clarified communication with HID device :-). To the left of each figure the circle with number inside is drawn. This circle specifies the step number of the algorithm. The detailed description of each step are presented in the table below.

Step Description
1 Get interface GUID for all HID Class devices located in the system. For this purpose HidD_GetHidGuid(Guid) function is used. Where ”Guid” is a pointer to the buffer that receives interface GUID for HID Class devices.
2 Receive handle to the device information set that contains all installed devices matched to the supplied HID GUID via call of the hDevInfo = SetupDiGetClassDevs(Guid, null, null, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT) function. Two flags DIGCF_DEVICEINTERFACE (return devices that support device interfaces for the specified device interface classes) and DIGCF_PRESENT (return only devices that are currently present in a system) are specified in the Flags parameter. We must delete the returned device information before exit from this function.
3 Next we start search loop for find HID device with predefined USB VID and PID. This loop must find our USB device withing received device information set. For this purpose we create ”index” variable that will point to the device interface in the received set. We must look over all interfaces belong to the HID device information set.
4 Enumerates the device interfaces that are contained in a device information set via SetupDiEnumDeviceInterfaces(hDevInfo, null, Guid, index, DeviceInterfaceData) function. We must receive information about the interface associated with ”index” value (number in the linked list of interfaces in the device information set). Function return boolean result. The zero result indicates that in the linked list is no more available interfaces, ie we finished search process and must go out from the loop. If returned value is true we must receive detailed data.
5 In this step we must receive details about a device interface. This step is divided into two parts. First, we need to get the length of the detailed data structure, and then allocate space and retrieve it. For request length of the detailed data structure we must call SetupDiGetDeviceInterfaceDetail(hDevInfo, DeviceInterfaceData, DeviceInterfaceDetailData, DeviceInterfaceDetailDataSize, reqlength, DeviceInfoData) function with parameters ”DeviceInterfaceDetailData” and ”DeviceInterfaceDetailDataSize” equal to zero. Calling this function will be as follows: SetupDiGetDeviceInterfaceDetail(hDevInfo, DeviceInterfaceData, null, 0, reqlength, null). After this call “reqlength” variable receives required buffer size for the device information. Next we must allocate space for the device path and call this function again: SetupDiGetDeviceInterfaceDetail(hDevInfo, DeviceInterfaceData, DeviceInterfaceDetailData, reqlength.getValue(), reqlength, null). The ”DeviceInterfaceDetailData.devicePath” now contains the valid path to the HID device specified by the “index” variable.
6 Open HID device with the kernel32 ”CreateFile” function. You must remember that GENERIC_READ and GENERIC_WRITE flags not used in ”dwDesiredAccess field” for system devices such as keyboard and mouse. In our hardware we use keyboard interface, so function call will looks as mentioned below: HandleToDevice = CreateFile(Native.toString(DeviceInterfaceDetailData.devicePath), 0, WinNT.FILE_SHARE_READ + WinNT.FILE_SHARE_WRITE, 0, WinNT.OPEN_EXISTING, WinNT.FILE_FLAG_OVERLAPPED, (WinNT.HANDLE) null).
7 In the step seven we must obtain a device's vendor information by executing HidD_GetAttributes(HandleToDevice, HIDAttributes) function. ”HIDAttributes” is a pointer to the allocated HIDD_ATTRIBUTES structure that contains attributes of the collection.
8 Now we must compare received device attributes (VID and PID) with specified earlier. If at least one of the specified attribute does not coincide with those obtained in the previous step, we need to close a previously opened device by using the CloseHandle(HandleToDevice) function, increment “index” variable and go to the top of the loop at the step 4. If device attributes coincide to the specified VID and PID, the process of finding a suitable HID device stops and we move on to the next step of the algorithm.
9 Finally, we have found and opened our USB HID device. Now we need to destroy device information list, created at the step two of our algorithm by executing SetupDiDestroyDeviceInfoList(hDevInfo) function and move to the last tenth phase of the algorithm.
10 Save received USB HID device handle into the ”HIDHandle” class member variable. Grab report descriptor data (preparsed data) via HidD_GetPreparsedData(HIDHandle, HIDPreparsedData) finction. After that we obtain a top-level collection's HIDP_CAPS structure: HidP_GetCaps(HIDPreparsedData.getValue(), HIDCapabilities) and reload a couple of useful constants ”InputeReportLength”, ”OutputReportLength” and ”FeatureReportLength” into the communication class member variables for further interaction with the USB device.

Table 1. Open USB Device process description.

Communication via Control Pipe

As we stated above, we use HID keyboard interface in our hardware. Device Interrupt IN Endpoint used for the keybord report generation. It turns out that the primary data communication channel (Interrupt IN) is engaged by the keyboard reports, we need to find another mechanism for interaction with the device. Communication with HID device

Picture 3. Communication with HID device.

Communication subsystem, that interacts with the system devices such as keyboard or mouse, use Control Transfers via Endpoint 0 for read or write data. In our case a user-mode application should use HidD_SetFeature and HidD_GetFeature routines to obtains and sets feature information in USB device. A HID report is a communication unit for HID Class devices. A report descriptor, specified in the device firmware, defines the formated structure with predefined length that will be used in data communication. Our device hold two reports. First is a Input Report, used for output keyboard data to the system input driver. Second is a Feature Report that specifies device configuration and settings. This report used for interaction with device (set or retrieve different options). If a device supports more than one report of the same type, each report is assigned a unique ID ”Rreport ID”. See the communication functions presented below:

/**
 * Method send Feature request to the USB HID device via Control 
 * transfers through Endpoint0.
 * 
 * @param   buffer      Transmitted Data buffer.
 * @param   buffersize  Size of the transmitted buffer.
 * @return  Returned status: 
 *          HID_DEVICE_SUCCESS - Transaction successfuly completed,
 *          HID_DEVICE_NOT_OPENED - Device is not opened,
 *          HID_DEVICE_TRANSFER_FAILED - Transaction completed with errors.
 */
public byte SetFeatureReport(byte[] buffer, short buffersize) {
 /* Check to see that the device is opened */
 if (HIDHandle.equals(WinBase.INVALID_HANDLE_VALUE)) {
     return HID_DEVICE_NOT_OPENED;
 }
 /* Write Feature report */
 boolean Status = Hid.INSTANCE.HidD_SetFeature(HIDHandle, buffer, buffersize);
 if (Status == false) {
     return HID_DEVICE_TRANSFER_FAILED;
 }
 else {
     return HID_DEVICE_SUCCESS;
 }
}     

Example 1. Send data to the device via Set Report Feature.

/**
 * Method retrieves Feature report from the USB HID device 
 * via Control transfer through Endpoint0.
 * @param   buffer      Received Data buffer.
 * @return  Returned status: 
 *                      HID_DEVICE_SUCCESS - Transaction successfuly completed,
 *                      HID_DEVICE_NOT_OPENED - Device is not opened,
 *                      HID_DEVICE_TRANSFER_FAILED - Transaction completed with errors.
 */
public byte GetFeatureReport(byte[] buffer) {
 /* Check to see that the device is opened */
 if (HIDHandle.equals(WinBase.INVALID_HANDLE_VALUE)) {
      return HID_DEVICE_NOT_OPENED;
 }
 /* Get Feature report */
 boolean Status = Hid.INSTANCE.HidD_GetFeature(HIDHandle, buffer, buffer.length);
 if (Status == false) {
     return HID_DEVICE_TRANSFER_FAILED;
 }
 else {
     return HID_DEVICE_SUCCESS;
 }
}

Example 2. Get data from the device via Get Report Feature.

Size of the transmitting buffer in the SetFeatureReport function as well as length of the reception buffer in the GetFeatureReport function must be equal to the Feature Report length. Feel free to add to this communication class two members that will transfer data through interrupt pipe via kernel32 ReadFile and WriteFile functions.

Java USB HID Communication Class in whole scope noted below.

communication.java
/* Copyright (c)2010, KSL Embedded (www.kslemb.com)
 * All rights reserved. 
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 1. Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright 
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the KSL EMBEDDED nor the names of its contributors 
 *    may be used to endorse or promote products derived from this software 
 *    without specific prior written permission.  
 *
 * THIS SOFTWARE IS PROVIDED BY THE KSL EMBEDDED AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE KSL ENBEDDED OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 * USB HID Communication class for Java, based on JNA (provide easy access to native shared libraries).
 *
 * Copyright (c)2010 KSL Embedded. 
 * Java class for communication with USB HID devices.
 * This version of the software (Windows release) includes next methods:
 * 1. SetVendorID() - set Vendor device Identifier used to open USB HID device.
 * 2. SetProductID() - set Vendor product Identifier used to open USB HID device.
 * 3. getHIDHandle() - retrieving handle to the HID device with specified VID & PID.
 * 4. isOpened() - check if USB HID device is opened.
 * 5. SetFeatureReport() - send SetFeature request to the device via Control pipe.
 * 6. GetFeatuteReport() - receive Feature request from the device via Control pipe.
 * 7. CloseHIDDevice() - close previously opened USB HID device.
 * 
 * @version 1.0
 * @author Konstantin Vovk <ksl@kslemb.com>
 * @author Vladimir Gapoyants <gp@kslemb.com>
 */
 
package hid;
 
import com.sun.jna.*;  
import com.sun.jna.ptr.*;  
import com.sun.jna.win32.*;  
import com.sun.jna.platform.win32.*;
 
public class communication {
 
    /** 
     * HID Communication class Return Codes 
     */
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Last operation executed successfully 
     */
    byte HID_DEVICE_SUCCESS             = 0x00;
    /** 
     * USB HID device specified by the VID and PID not detected in the system 
     */
    byte HID_DEVICE_NOT_FOUND           = 0x01;
    /** 
     * HID Device not opened
     */
    byte HID_DEVICE_NOT_OPENED          = 0x02;
    /** 
     * HID Device alredy opened 
     */
    byte HID_DEVICE_ALREADY_OPENED      = 0x03;
    /** 
     * Transfer timeout for Read/Write operation 
     */
    byte HID_DEVICE_TRANSFER_TIMEOUT    = 0x04;
    /** 
     * Error detected in last data transaction 
     */
    byte HID_DEVICE_TRANSFER_FAILED     = 0x05;
    /** 
     * Can't receive HID device description 
     */
    byte HID_DEVICE_CANNOT_GET_HID_INFO = 0x06;
    /** 
     * HID device invalid handle value 
     */
    byte HID_DEVICE_HANDLE_ERROR        = 0x07;
    /** 
     * HID device invalid supplied buffer size 
     */
    byte HID_DEVICE_INVALID_BUFFER_SIZE = 0x08;
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * USB HID Device Vendor ID 
     */
    private short vendorID;
    /** 
     * USB HID Device Product ID 
     */
    private short productID;
 
    //-------------------------------------------------------------------------------------------------------------------    
    /** 
     * Set VID used to open USB HID device 
     * 
     * @param   VendorID    Vendor ID used to open USB HID device.
     */
    public void SetVendorID(short VendorID) {
        vendorID = VendorID;
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Set PID used to open USB HID device 
     * 
     * @param   ProductID    Product ID used to open USB HID device.
     */
    public void SetProductID(short ProductID) {
        productID = ProductID;
    }
 
    /** 
     * HID device Input/Output/Feature Report buffers length 
     */
    //-------------------------------------------------------------------------------------------------------------------    
    /** 
     * Input Report buffer length. 
     */
    private short InputReportLength;
    /** 
     * Output Report buffer length. 
     */
    private short OutputReportLength;
    /** 
     * Feature Report buffer length. 
     */
    private short FeatureReportLength;
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Retrieve length of the HID Input Report.
     */ 
    public short GetInputReportLength() {
        return InputReportLength;
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Retrieve length of the HID Output Report 
     */ 
    public short GetOutputReportLength() {
        return OutputReportLength;
    }
 
    //-------------------------------------------------------------------------------------------------------------------    
    /** 
     * Retrieve length of the HID Feature Report 
     */ 
    public short GetFeatureReportLength() {
        return FeatureReportLength;
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Handle to the opened USB HID Device 
     */
    private WinNT.HANDLE HIDHandle;
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Windows GUID structure.
     */
    public static class GUID extends Structure {
        public int      Data1;
        public short    Data2;
        public short    Data3;
        public byte     Data4[] = new byte[8];
}
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Handle definition.
     */
    public static class HDEVINFO extends WinNT.HANDLE {
    }
 
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set. 
     */
    public static class SP_DEVINFO_DATA extends Structure {
        public SP_DEVINFO_DATA() {
            ClassGuid = new GUID();
        }
        /** 
         * The size, in bytes, of the SP_DEVINFO_DATA structure. 
         */
        public int  cbSize;
        /** 
         * Device setup class GUID 
         */ 
        public GUID ClassGuid;
        /** 
         * Handle to the device instance (handle to the devnode) 
         */
        public int  DevInst;
        /** 
         * Reserved. For internal use only. 
         */
        public int  Reserved;
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * An SP_DEVICE_INTERFACE_DATA structure defines a device interface in a device information set. 
     */
    public static class SP_DEVICE_INTERFACE_DATA extends Structure {
        public SP_DEVICE_INTERFACE_DATA() {
            InterfaceClassGuid = new GUID();
        }
        /** 
         * The size, in bytes, of the SP_DEVICE_INTERFACE_DATA structure. 
         */
        public int  cbSize;
        /** 
         * The GUID for the class to which the device interface belongs. 
         */
        public GUID InterfaceClassGuid;
        /** 
         * Can be one or more of the following:
         *  SPINT_ACTIVE    - The interface is active (enabled).
         *  SPINT_DEFAULT   - The interface is the default interface for the device class.
         *  SPINT_REMOVED   - The interface is removed.  
         */
        public int  Flags;
        /** 
         * Reserved. Do not use. 
         */
        public int  Reserved;
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * An SP_DEVICE_INTERFACE_DETAIL_DATA structure contains the path for a device interface. 
     */
    public static class SP_DEVICE_INTERFACE_DETAIL_DATA extends Structure {
        /** 
         * The size, in bytes, of the fixed portion of the SP_DEVICE_INTERFACE_DETAIL_DATA structure. 
         */
        public int cbSize;
        /** 
         * A NULL-terminated string that contains the device interface path. This path can be passed to Win32 functions CreateFile. 
         */
        public char[] devicePath = new char[1];
        public SP_DEVICE_INTERFACE_DETAIL_DATA() {
            setAlignType(Structure.ALIGN_NONE);
        }        
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * The HIDD_ATTRIBUTES structure contains vendor information about a HIDClass device. 
     */
    public static class HIDD_ATTRIBUTES extends Structure {
        /** 
         * Specifies the size, in bytes, of a HIDD_ATTRIBUTES structure. 
         */
        public int   Size;
        /** 
         * Specifies a HID device's vendor ID. 
         */
        public short VendorID;
        /** 
         * Specifies a HID device's product ID. 
         */
        public short ProductID;
        /** 
         * Specifies the manufacturer's revision number for a HIDClass device. 
         */
        public short VersionNumber;
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * The HIDP_CAPS structure contains information about a top-level collection's capability (defined by the usage, reports, link, and controls). 
     */
    public static class HIDP_CAPS extends Structure {
        /** 
         * Specifies a top-level collection's usage ID. 
         */
        public short Usage;
        /** 
         * Specifies the top-level collection's usage page. 
         */
        public short UsagePage;
        /** 
         * Specifies the maximum size, in bytes, of the input reports including the report ID. 
         */
        public short InputReportByteLength;
        /** 
         * Specifies the maximum size, in bytes, of all the output reports including the report ID. 
         */
        public short OutputReportByteLength;
        /** 
         * Specifies the maximum length, in bytes, of all the feature reports including the report ID. 
         */
        public short FeatureReportByteLength;
        /** 
         * Reserved for internal system use. 
         */
        public short Reserved[] = new short[17];
        /** 
         * Specifies the number of HIDP_LINK_COLLECTION_NODE structures, returned for this top-level collection by HidP_GetLinkCollectionNodes. 
         */
        public short NumberLinkConnectionNodes;
        /** 
         * Specifies the number of input HIDP_BUTTON_CAPS structures that HidP_GetButtonCaps returns. 
         */
        public short NumberInputButtonCaps;
        /** 
         * Specifies the number of input HIDP_VALUE_CAPS structures that HidP_GetValueCaps returns. 
         */
        public short NumberInputValueCaps;
        /** 
         * Specifies the number of data indices assigned to buttons and values in all input reports. 
         */
        public short NumberInputDataIndices;
        /** 
         * Specifies the number of output HIDP_BUTTON_CAPS structures that HidP_GetButtonCaps returns. 
         */
        public short NumberOutputButtonCaps;
        /** 
         * Specifies the number of output HIDP_VALUE_CAPS structures that HidP_GetValueCaps returns. 
         */
        public short NumberOutputValueCaps;
        /** 
         * Specifies the number of data indices assigned to buttons and values in all output reports. 
         */
        public short NumberOutputDateIndices;
        /** 
         * Specifies the total number of feature HIDP_BUTTONS_CAPS structures that HidP_GetButtonCaps returns. 
         */
        public short NumberFeatureButtonCaps;
        /** 
         * Specifies the total number of feature HIDP_BUTTONS_CAPS structures that HidP_GetButtonCaps returns. 
         */
        public short NumberFeatureValueCaps;
        /** 
         * Specifies the number of data indices assigned to buttons and values in all feature reports. 
         */
        public short NumberFeatureDataIndices;
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Declare a Java interface that holds the native "hid.dll" library methods by extending the W32API interface. 
     */
    public interface Hid extends WinNT {
        /** 
         * Load a library interface from the "hid.dll" shared library 
         */
        Hid INSTANCE = (Hid) Native.loadLibrary("hid", Hid.class, W32APIOptions.UNICODE_OPTIONS);
 
        /** 
         * Method returns the device interface GUID for HIDClass devices. 
         */
        void HidD_GetHidGuid(GUID Guid);
        /** 
         * Method returns the attributes of a specified top-level collection. 
         */
        int HidD_GetAttributes(WinNT.HANDLE Handle, HIDD_ATTRIBUTES HIDAttributes);
        /** 
         * Method returns a top-level collection's preparsed data (report descriptor associated with a top-level collection) 
         */
        int HidD_GetPreparsedData(WinNT.HANDLE Handle, IntByReference HIDPreparsedData);
        /** 
         * Method returns a top-level collection's HIDP_CAPS structure. 
         */
        int HidP_GetCaps(int HIDPreparsedData, HIDP_CAPS HIDCapabilities);
        /** 
         * Send a feature report to the specified top-level collection. 
         */
        boolean HidD_SetFeature(WinNT.HANDLE HidDeviceObject, byte[] ReportBuffer, int ReportBufferLength);
        /** 
         * Get a feature report from a specified top-level collection. 
         */
        boolean HidD_GetFeature (WinNT.HANDLE HidDeviceObject, byte[] ReportBuffer, int ReportBufferLength);
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Declare a Java interface that holds the native "setupapi.dll" library methods by extending the W32API interface. 
     */
    public interface Setupapi extends WinNT {
        /** 
         * Load a library interface from the "setupapi.dll" shared library 
         */
        Setupapi INSTANCE = (Setupapi) Native.loadLibrary("setupapi", Setupapi.class, W32APIOptions.UNICODE_OPTIONS);
 
       /** 
        * SetupDiGetClassDevs Flag constants.
        * 
        * Specifies control options that filter the device information elements that are added to the device information set. 
        */
        /** 
         * Return only the device that is associated with the system default device interface, if one is set, for the specified device interface classes. 
         */
        public static int DIGCF_DEFAULT         = 0x00000001; 
        /** 
         * Return only devices that are currently present in a system. 
         */
        static int DIGCF_PRESENT                = 0x00000002;
        /** 
         * Return a list of installed devices for all device setup classes or all device interface classes. 
         */
        public static int DIGCF_ALLCLASSES      = 0x00000004; 
        /** 
         * Return only devices that are a part of the current hardware profile. 
         */
        public static int DIGCF_PROFILE         = 0x00000008;
        /** 
         * Return devices that support device interfaces for the specified device interface classes. 
         * 
         * This flag must be set in the Flags parameter if the Enumerator parameter specifies a device instance ID. 
         */
        public static int DIGCF_DEVICEINTERFACE = 0x00000010; 
 
        /** 
         * Method returns a device information set that contains all devices of a specified class. 
         */
        HDEVINFO SetupDiGetClassDevs(GUID Guid, String Enumerator, WinDef.HWND Parent, int Flags);
        /** 
         * Method returns a context structure for a device interface element of a device information set. 
         * 
         * Each call returns information about one device interface.
         * The function can be called repeatedly to get information about several 
         * interfaces exposed by one or more devices. 
         */
        int SetupDiEnumDeviceInterfaces(HDEVINFO DeviceInfoSet, SP_DEVINFO_DATA DeviceInfoData, GUID Guid, int MemberIndex, SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
        /** 
         * Method returns details about a particular device interface. 
         */
        int SetupDiGetDeviceInterfaceDetail(HDEVINFO DeviceInfoSet, SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, SP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData, int DeviceInterfaceDetailDataSize, IntByReference RequiredSize, SP_DEVINFO_DATA DeviceInfoData);
        /** 
         * Method destroys a device information set and frees all associated memory. 
         */
        int SetupDiDestroyDeviceInfoList(HDEVINFO  DeviceInfoSet);
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Declare a Java interface that holds the native "kernel32.dll" library methods by extending the W32API interface. 
     */
    public interface Kernel32RW extends Kernel32 {
 
        Kernel32 INSTANCE = (Kernel32RW) Native.loadLibrary("kernel32", Kernel32RW.class, W32APIOptions.UNICODE_OPTIONS);
 
        /** 
         * CreateFile constants 
         */
        /** 
         * Enable read access 
         */
        int GENERIC_READ        = 0x80000000;
        /** 
         * Enable write access 
         */
        int GENERIC_WRITE       = 0x40000000;
 
        /** 
         * Read data from USB HID device.
         */
        int ReadFile(WinNT.HANDLE Handle, byte[] buffer, int nNumberOfBytesToRead,  IntByReference NumberOfBytesRead,  IntByReference Overlapped);
        /** 
         * Write data to the USB HID device.
         */
        int WriteFile(WinNT.HANDLE Handle, byte[] buffer, int NumberOfBytesToWrite, IntByReference NumberOfBytesWritten, IntByReference Overlapped);
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Debug console output.
     */
    private void debug(String err) {
        System.out.println(err);
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Get last error description.
     * 
     * @param   code    Sysyem error code.
     * @return          Error message for the specified error code.
     */
    private String getSystemError(int code) {
        Kernel32 lib = Kernel32.INSTANCE;
        PointerByReference pref = new PointerByReference();
        lib.FormatMessage(
            WinBase.FORMAT_MESSAGE_ALLOCATE_BUFFER | WinBase.FORMAT_MESSAGE_FROM_SYSTEM | WinBase.FORMAT_MESSAGE_IGNORE_INSERTS, 
            null, 
            code, 
            0, 
            pref, 
            0, 
            null);
        String s = pref.getValue().getString(0, !Boolean.getBoolean("w32.ascii"));
        lib.LocalFree(pref.getValue());
        return s;
    } 
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Open USB HID device with the previously specified VID and PID.
     * 
     * @note For the system input device (keyboard, mouse) the dwDesiredAccess field in CreateFile must be '0'.
     * @return          'true' if the HID device with specified VID and PID exists in system and successfully opened.
     */ 
     boolean getHIDHandle() {
 
        WinNT.HANDLE HandleToDevice = null;
        GUID Guid = new GUID();
 
        /** Get the GUID for all system USB HID devices. */
        Hid.INSTANCE.HidD_GetHidGuid(Guid);
 
        /** Receive a handle to the device information set for all installed devices. */ 
        HDEVINFO hDevInfo = Setupapi.INSTANCE.SetupDiGetClassDevs(Guid, null, null, Setupapi.DIGCF_DEVICEINTERFACE | Setupapi.DIGCF_PRESENT);
 
        int index = 0;
        do {
            HandleToDevice = WinBase.INVALID_HANDLE_VALUE;
 
            SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
            DeviceInterfaceData.cbSize = DeviceInterfaceData.size();
            /* Query the device using the index to get the interface data */
            int result = Setupapi.INSTANCE.SetupDiEnumDeviceInterfaces(hDevInfo, null, Guid, index, DeviceInterfaceData);
            /* If no more HID devices at the root hub - LastError = ERROR_NO_MORE_ITEMS */
            if (result == 0) {
                /* Go out from the device search loop */
                break;
            }
            /* A successful query was made, use it to get the detailed data of the device */
            IntByReference reqlength = new IntByReference();
            /* Obtain the length of the detailed data structure, and then allocate space and retrieve it */
            result = Setupapi.INSTANCE.SetupDiGetDeviceInterfaceDetail(hDevInfo, DeviceInterfaceData, null, 0, reqlength, null);
 
            // Create SP_DEVICE_INTERFACE_DETAIL_DATA structure and set appropriate length for device Path */
            SP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData      = new SP_DEVICE_INTERFACE_DETAIL_DATA();
            SP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailDataDummy = new SP_DEVICE_INTERFACE_DETAIL_DATA();
            DeviceInterfaceDetailData.cbSize = DeviceInterfaceDetailDataDummy.size();
            DeviceInterfaceDetailData.devicePath = new char[reqlength.getValue()];
            /* Obtain DEVICE_INTERFACE_DETAIL_DATA structure for grab path for HID device */
            result = Setupapi.INSTANCE.SetupDiGetDeviceInterfaceDetail(hDevInfo, DeviceInterfaceData, DeviceInterfaceDetailData, reqlength.getValue(), reqlength, null);
            if (result == 0) {
                debug("SetupDiGetDeviceInterfaceDetail: " + getSystemError(Kernel32.INSTANCE.GetLastError()));
                break;
            }    
 
            /* Kernel32RW.GENERIC_READ | Kernel32RW.GENERIC_WRITE not used in dwDesiredAccess field for system devices such a keyboard or mouse */
            int shareMode = WinNT.FILE_SHARE_READ | WinNT.FILE_SHARE_WRITE;
            int Access = 0; // WinNT.GENERIC_WRITE | Kernel32RW.GENERIC_READ;
            HandleToDevice = Kernel32.INSTANCE.CreateFile(
                Native.toString(DeviceInterfaceDetailData.devicePath), 
                Access, 
                shareMode, 
                null, 
                WinNT.OPEN_EXISTING, 
                WinNT.FILE_FLAG_OVERLAPPED, 
                (WinNT.HANDLE)null);
            if (HandleToDevice == WinBase.INVALID_HANDLE_VALUE) {
                debug("For device with index " + Integer.toString(index) + " CreateFile: " + getSystemError(Kernel32.INSTANCE.GetLastError()));
            }    
            /* Create HIDD_ATTRIBUTES structure */
            HIDD_ATTRIBUTES HIDAttributes = new HIDD_ATTRIBUTES();
            HIDAttributes.Size = HIDAttributes.size();
            /* Fill HIDD_ATTRIBUTES structure */
            result = Hid.INSTANCE.HidD_GetAttributes(HandleToDevice, HIDAttributes);
            if (result == 0) {
                debug("For device with index " + Integer.toString(index) + " HidD_GetAttributes: " + getSystemError(Kernel32.INSTANCE.GetLastError()));
            }
            /* Check VID & PID of the opened device */
            if (HIDAttributes.VendorID == vendorID && HIDAttributes.ProductID == productID) {
                debug("Device is found");
                break;
            }
            else {
                /* Close HID Device */
                Kernel32.INSTANCE.CloseHandle(HandleToDevice);
            }
            /* Check the next HID device for the valid VID and PID */
            index++;
        } while (true);
 
        Setupapi.INSTANCE.SetupDiDestroyDeviceInfoList(hDevInfo);
 
        /* Save Handle to the opened device */
        HIDHandle = HandleToDevice;
 
        if (HandleToDevice.equals(WinBase.INVALID_HANDLE_VALUE)) {
            debug("Device with VID=0x" + Integer.toHexString(vendorID) + " and PID=0x" + Integer.toHexString(productID) + " not found");
            return false;
        }
        else {
            IntByReference HIDPreparsedData = new IntByReference();
            Hid.INSTANCE.HidD_GetPreparsedData(HandleToDevice, HIDPreparsedData); 
            HIDP_CAPS HIDCapabilities = new HIDP_CAPS();
            int result = Hid.INSTANCE.HidP_GetCaps(HIDPreparsedData.getValue(), HIDCapabilities);
            InputReportLength = HIDCapabilities.InputReportByteLength;
            OutputReportLength = HIDCapabilities.OutputReportByteLength;
            FeatureReportLength = HIDCapabilities.FeatureReportByteLength;
            return true;
        }
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /**
     * Check if USB HID device already opened.
     * @return          'true' if the the HID device is alredy opend. 'false' otherwise.
     */
    public boolean isOpened() {
        if (HIDHandle != WinBase.INVALID_HANDLE_VALUE) {
            return true;
        }
        else {
            return false;
        }
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /** 
     * Close already opened USB HID device.
     */
    public void CloseHIDDevice () {
        if (HIDHandle != WinBase.INVALID_HANDLE_VALUE) {
            /* Close HID Device */
            Kernel32.INSTANCE.CloseHandle(HIDHandle);
        }
    }
 
    //-------------------------------------------------------------------------------------------------------------------
    /**
     * Method send Feature request to the USB HID device via Control transfer through Endpoint0.
     * 
     * @param   buffer      Transmitted Data buffer.
     * @param   buffersize  Size of the transmitted buffer (must be equal to Feature Report length).
     * @return  Returned status: HID_DEVICE_SUCCESS - Transaction successfuly completed,
     *                           HID_DEVICE_NOT_OPENED - Device is not opened,
     *                           HID_DEVICE_TRANSFER_FAILED - Transaction completed with errors.
     */
    public byte SetFeatureReport(byte[] buffer, short buffersize) {
        /* Check to see that the device is opened */
        if (HIDHandle.equals(WinBase.INVALID_HANDLE_VALUE)) {
            return HID_DEVICE_NOT_OPENED;
        }
        /* Write Feature report */
        boolean Status = Hid.INSTANCE.HidD_SetFeature(HIDHandle, buffer, buffersize);
        if (Status == false) {
            return HID_DEVICE_TRANSFER_FAILED;
        }
        else {
            return HID_DEVICE_SUCCESS;
        }
    }     
 
    //-------------------------------------------------------------------------------------------------------------------
    /**
     * Method retrieves Feature report from the USB HID device via Control transfer through Endpoint0.
     * @param   buffer      Received Data buffer.
     * @return  Returned status: HID_DEVICE_SUCCESS - Transaction successfuly completed,
     *                           HID_DEVICE_NOT_OPENED - Device is not opened,
     *                           HID_DEVICE_TRANSFER_FAILED - Transaction completed with errors.
     */
    public byte GetFeatureReport(byte[] buffer) {
        /* Check to see that the device is opened */
        if (HIDHandle.equals(WinBase.INVALID_HANDLE_VALUE)) {
            return HID_DEVICE_NOT_OPENED;
        }
        /* Get Feature report */
        boolean Status = Hid.INSTANCE.HidD_GetFeature(HIDHandle, buffer, buffer.length);
        if (Status == false) {
            return HID_DEVICE_TRANSFER_FAILED;
        }
        else {
            return HID_DEVICE_SUCCESS;
        }
    }
 
//-------------------------------------------------------------------------------------------------------------------    
    public communication() {
        super();
        HIDHandle = WinBase.INVALID_HANDLE_VALUE;
    }
}