Author Topic: USB Host Software using VB.Net 2010  (Read 38254 times)

Geoff

  • Member
  • ***
  • Posts: 8
USB Host Software using VB.Net 2010
« on: April 26, 2011, 02:33:36 am »
Hi,

Although I am relatively new to USB interface development, I have learned quite a lot from my copy of USB Complete 4th Edition.  Thanks to Jan Axelson.

However, I have been unsuccessful in performing interrupt-driven communications with Host software written using Visual Basic 2010 (includes .NET Framework V4.0) - on an XP (SP3) based PC.

Can anyone please assist me ?

------------

The custom peripheral device has been successfully enumerated.  This has been verified using a GraphicUSB sniffer from MQP Electronics, and recognized correctly by the Device Manager.

The peripheral has been created to support an input Report (12 bytes), an output Report (7 bytes) and a feature report (6 bytes).
The peripheral has also been created to support:
*** Configuration 1
 ** Interface 0 (alt 0) HID
    - Class Descriptor
    * Endpoint 2-IN INTERRUPT
    * Endpoint 1-OUT INTERRUPT

Using VB, I can successfully find the peripheral device, and I can send data to the peripheral device using the command:
              success = HidD_SetFeature(hidHandle, outFeatureReportBuffer, outFeatureReportBuffer.Length)

However after many,many attempts I have been unable to send data to the peripheral device using the command:
              success = HidD_SetOutputReport(hidHandle, outputReportBuffer, outputReportBuffer.Length)

Of course, using the HidD_SetFeature command uses Endpoint 0 (command endpoint) whereas I wish to use Endpoint 1 (the output endpoint) using the HidD_SetOutputReport command.

Jan Axelson's "GenericHid.vb" example host software was built using Visual Studio 2008 Standard Edition with the .NET Framework V2.0.    I have rebuilt this example using VS 2010 with .NET 4.0 .   After setting the VendorID and ProductID, the peripheral device is successfully detected, with the message:

"Device detected:  VendorID=B6A  ProductID = ABE1  The device is a system .  Windows 2000 and Windows XP obtain exclusive access to Input and Output reports for this devices.  Applications can access Feature reports only. "

Does this mean that XP can never send output reports to Endpoint 1 ?

I hope that someone can assist me.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: USB Host Software using VB.Net 2010
« Reply #1 on: April 26, 2011, 10:18:23 am »
If the descriptors identify the device as a system mouse or keyboard, Windows takes exclusive access to Input and Output reports.

For other HIDs, to use interrrupt transfers, use ReadFile and WriteFile, not HidD_ functions.

Jan

Geoff

  • Member
  • ***
  • Posts: 8
Re: USB Host Software using VB.Net 2010
« Reply #2 on: April 27, 2011, 07:32:34 am »
Hi Jan,

Thank you for your response comments.

The descriptors for the HID device define it to be "user defined" - and not a system mouse or keyboard.   I have tried many times to get ReadFile and WriteFile to work, however they always fail.   Currently the only method by which I am able to transfer data to/from the peripheral device is via HidD_SetFeature and HidD_GetFeature VB commands.

(a) The device is successfully detected, and registered for device notifications.
(b) The writeHandle is created using VB command:
        writeHandle = CreateFile(CapturedDevicePathName, GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
(c) The writeHandle is confirmed OK since writeHandle.IsInvalid = False
(d) The output report buffer is initialized with some data.
(e) The output report buffer is sent to the peripheral device using VB command:
        WriteFile(writeHandle, OutputReportBuffer, OutputReportBuffer.Length, NumberOfBytesWritten, IntPtr.Zero)
(f) The number of bytes written to the peripheral device is zero (ie. NumberofBytesWritten=0) and the Last Error Code (Err.LastDllError) is "1" (ie. "incorrect function").
(g) The readHandle is attempted to be created using VB command:
        readHandle = CreateFile(CapturedDevicePathName, GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0)
(h) The readHandle failed since readHandle.IsInvalid = True   with the Last Error Code (Err.LastDllError) = "0".

The peripheral device is defined as:
  1. Configuration Descriptor: 9 bytes, Type=2, TotalLength=0041 bytes, NumInterfaces=1, ConfigValue=1, Configuration=0, Attributes=self-powered + RWU supported, Max Power=2mA
  2. Interface Descriptor: 9 bytes, Type=4, Interface=0, No alternate, 2 endpoints, InterfaceClass=HID, SubClass=0, Protocol=0, Interface=0
  3. HID Descriptor: 9 bytes, Type=33=HID, HID Rev 1.1, country code = 0, 1 report descriptor, DescriptorType=34=Report, Report Descriptor Length=47
  4. EndPoint Descriptor: 7 bytes, Type=5=EndPoint, EndPointAddress=82=EP2-IN Attributes=interrupt(03), MaxPacketSize=0064, Poll Interval=10msec
  5. EndPoint Descriptor: 7 bytes, Type=5=EndPoint, EndPointAddress=01=EP1-OUT Attributes=control(03), MaxPacketSize=0064, Poll Interval=10msec

This has been verified (using USB Analyzer) as:

Device Descriptor:
        bLength = 18
        bDescriptorType = 1  (device)
        bcdUSB = 0x0110      (Rev 1.1)
        bDeviceClass = 0x00
        bDeviceSubClass = 0x00
        bDeviceProtocol = 0x00
        bMaxPacketSize0 = 64
        idVendor = 0x0B6A
        idProduct = 0xABE1
        bcdDEvice = 0x0100
        iManufacturer = 1
        iProduct = 2
        iSerialNumber = 3
        bNumCOnfigurations = 1

Configuration Descriptor:
        bLength = 9
        bDescriptorType = 2 (configuration)
        wTotalLength = 41
        bNumInterfaces = 1
        bConfigurationValue = 1
        iConfiguration = 0
        bmAttributes = 1 (self-powered)
        bmAttributes = 1 (remote wakeup)
        bMaxPower = 2 mA

Interface Descriptor:
        bLength = 9
        bDescriptorType = 4 (interface)
        bInterfaceNumber = 0
        bAlternateSetting = 0
        bNumEndpoint = 2
        bInterfaceClass = 0x03    (HID)
        bInterfaceSubClass = 0x00
        bInterfaceProtocol = 0x00
        iInterface = 0

HID Descriptor:
        bLength = 9
        bDescriptorType = 0x21  (HID)
        bcdHID = 0x0110
        bCountryCode = 0
        bNumDescriptors = 1
        bDescriptorType = REPORT   (type 34)
        wDescriptorLength = 47

EndPoint Descriptor:
        bLength = 7
        bDescriptorType = 5 (Endpoint)
        bEndpointAddress = 0x82   (Endpoint 2 - IN)
        bmAttributes = 0x03  (interrupt)
        wMaxPacketSoze = 0x0040  (64)
        bInterval = 0x0A  (10ms)

EndPoint Descriptor:
        bLength = 7
        bDescriptorType = 5 (Endpoint)
        bEndpointAddress = 0x01   (Endpoint 1 - OUT)
        bmAttributes = 0x03  (interrupt)
        wMaxPacketSoze = 0x0040  (64)
        bInterval = 0x01  (1ms)

Report Descriptor: VENDOR-DEFINED Device (Input Report of 12 bytes, Output Report of 7 bytes, Feature Report of 8 bytes)

   0x06,0xFFA0,       // Usage Page (vendor defined)
   0x09,0x01,          // Usage (vendor defined)
   0xA1,0x01,          // Collection
  
   0x09,0x01,          //   Usage (vendor defined)
   0x15,0x00,          //   Logical Minimum = 0
   0x26,0x00FF        //   Logical Maximum = 255
   0x95,0x0C,          //   Report Count = 12
   0x75,0x08,          //   Report Size = 8
   0x81,0x02,          //  Input(Data,Variable,Absolute)

   0x09,0x05,          //   Usage (vendor defined)
   0x15,0x00,          //   Logical Minimum = 0
   0x26,0x00FF        //   Logical Maximum = 255
   0x95,0x06,          //   Report Count = 6
   0x75,0x08,          //   Report Size = 8
   0xB1,0x02,          //  Feature(Data,Variable,Absolute)

   0x09,0x04,          //   Usage (vendor defined)
   0x15,0x00,          //   Logical Minimum = 0
   0x26,0x00FF        //   Logical Maximum = 255
   0x95,0x07,          //   Report Count = 7
   0x75,0x08,          //   Report Size = 8
   0x91,0x02,          //  Output(Data,Variable,Absolute)
  
   0xC0                  // End Collection  


I hope that this information will assist in resolving the faulty operation of the VB interface communicating with the peripheral device.  However, I don't know whether this is the result of faulty specification of the peripheral device or faulty VB commands trying to access the report structures.

Thank you.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: USB Host Software using VB.Net 2010
« Reply #3 on: April 27, 2011, 09:50:32 am »
Do the Usages and report lengths that HidP_GetCaps returns in HidD_Caps match what's in the report descriptor?

Is the WriteFile buffer at least 8 bytes with the first byte =0?

Jan


Geoff

  • Member
  • ***
  • Posts: 8
Re: USB Host Software using VB.Net 2010
« Reply #4 on: April 27, 2011, 05:39:56 pm »
Hi Jan,

The short answer: is "yes" and "yes".

The long answer is:  please see my VB code, and the results from execution of this code.

Thank you for your assistance and patience.

-----------

The following is the VB code used to perform a WriteFile (following the successful finding of the matching PID/VID).  Is there something incorrect in this sequence ?


    Private writeHandle As SafeFileHandle
    Dim success As Boolean
    Dim preparsedData As IntPtr
    Dim Capabilities As HIDP_CAPS
    Dim result As Int32
    Dim vcSize As Int32 = Capabilities.NumberInputValueCaps
    Dim valueCaps(vcSize - 1) As Byte
    Dim CapturedDevicePathName As String

    writeHandle = CreateFile(CapturedDevicePathName, GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
    If Not (writeHandle.IsInvalid) Then
        success = HidD_GetPreparsedData(writeHandle, preparsedData)
        result = HidP_GetCaps(preparsedData, Capabilities)
        If (result <> 0) Then
            result = HidP_GetValueCaps(HidP_Input, valueCaps, vcSize, preparsedData)
            Array.Resize(OutputReportBuffer, Capabilities.OutputReportByteLength)

            OutputReportBuffer(0) = CByte("0")
            OutputReportBuffer(1) = CByte("1")
            OutputReportBuffer(2) = CByte("2")
            OutputReportBuffer(3) = CByte("3")
            OutputReportBuffer(4) = CByte("4")
            OutputReportBuffer(5) = CByte("5")
            OutputReportBuffer(6) = CByte("6")
            OutputReportBuffer(7) = CByte("7")

            WriteFile(writeHandle, OutputReportBuffer, OutputReportBuffer.Length, NumberOfBytesWritten, IntPtr.Zero)

            lstResults.Items.Add("Last Error Code = " & Err.LastDllError)
            lstResults.Items.Add("NumberOfBytesWritten=" & NumberOfBytesWritten)

            lstResults.Items.Add("  Usage: " & Hex(Capabilities.Usage))
            lstResults.Items.Add("  Usage Page: " & Hex(Capabilities.UsagePage))
            lstResults.Items.Add("  Input Report Byte Length: " & Capabilities.InputReportByteLength)
            lstResults.Items.Add("  Feature Report Byte Length: " & Capabilities.FeatureReportByteLength)
            lstResults.Items.Add("  Output Report Byte Length: " & Capabilities.OutputReportByteLength)
        End If
    End If


The result of executing this code is:
  "Last Error Code = 1"
  "NumberOfBytesWritten=0"
  "  Usage: 1"
  "  Usage Page: FFA0"
  "  Input Report Byte Length: 13"
  "  Feature Report Byte Length: 7"
  "  Output Report Byte Length: 8"

This is completely consistent with the Report Descriptor which includes:

   0x95,0x0C,          //   Report Count = 12
   0x75,0x08,          //   Report Size = 8
   0x81,0x02,          //  Input(Data,Variable,Absolute)

   0x95,0x06,          //   Report Count = 6
   0x75,0x08,          //   Report Size = 8
   0xB1,0x02,          //  Feature(Data,Variable,Absolute)

   0x95,0x07,          //   Report Count = 7
   0x75,0x08,          //   Report Size = 8
   0x91,0x02,          //  Output(Data,Variable,Absolute)

ie. the Output Report Buffer has a size of 7 bytes, hence the OutputReportBuffer has elements 0 through 7, where element 0 contains "0".

Can you see something incorrect in the above sequence ?


Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: USB Host Software using VB.Net 2010
« Reply #5 on: April 27, 2011, 10:48:00 pm »
This isn't a solution, but the latest Generic HID code on my HID page uses Filestreams instead of ReadFile and WriteFile due to an InvalidOverlappedToPinvoke error on compiling. I don't think that error is your problem, however.

Are you editing my example or creating your own from scratch? If it's the latter, do the API declarations match what I used?

Jan

Geoff

  • Member
  • ***
  • Posts: 8
Re: USB Host Software using VB.Net 2010
« Reply #6 on: April 28, 2011, 10:23:26 am »
The code used in my VB application is based on the contents of USB Complete 4th Edition, and on the GenericHID code (Version 4.6).

I have now downloaded Version 5.0 of GenericHID.

Upon running GenericHID "as is" (built under VB 2010), the following is displayed upon discovery of the device:

"
The device is a system .
Windows 2000 and Windows XP obtain exclusive access to Input and Output reports for this devices.
Applications can access Feature reports only.
"

Selection of "Exchange Input and Output Reports" radio button, and the "Use ControlTransfers Only" checkbox, and then pressing "Send and Receive Data Once" button resulted in:

"
Invalid handle.  The device is probably a system mouse or keyboard.
No attempt to write an Output report or read and Input report was made.
"

The same response was received for selection of "Exchange Input and Output Reports" radio button only, and for "Exchange Feature Reports" radio button only.

Analysing the code execution shows that once the device has been detected, the CreateFile command with dwDesiredAccess = "GENERIC_READ Or GENERIC_WRITE" has failed.

The capabilities "UsagePage" has value of -96 (consistent with "Usage Page: FFA0" from the report descriptor) , and the capabilities "Usage" has value of 1 (consistent with "Usage: 1" from the report descriptor).

----------

I attempted one change to the Version 5.0 GenericHID code, and that was to modify the CreateFile command with dwDesiredAccess = "GENERIC_READ Or GENERIC_WRITE" to only have dwDesiredAccess = "GENERIC_WRITE".

The CreateFile now returns a valid result ... although the code then traps/throws me out immediately without any data transmission.

As best I can guess, the problem seems to reside with how the VB code (through Windows XP) perceives the peripheral device.   All development work and subsequent testing (to date) has been done on my main (XP SP3) PC.   This PC has endured a considerable amount of faulty report descriptors during development.  Is it possible that Windows has retained a previous (faulty) report descriptor ?

----------

I briefly borrowed my wife's Vista PC, and ran the Version 5.0 GenericHID code "as is".   The peripheral device emumerated successfully.  Selecting "Exchange Input and Output Reports" radio button only, and then pressing the "Once" button worked !   An output report was written !  Woo Hoo !
"
Output Report ID: 00
Output Report Data
01
81
00
00
00
00
00
The attempt to read a report timed out.
"

And then I got a .Net framework exception - although the output data (7 bytes) was confirmed as received on my USB analyzer on Endpoint 0.  The output report is specified to be 7 bytes long (good) but the output transmission should have occurred on EndPoint 1 - as specified in the configuration descriptor.

I tried again with the "Exchange Input and Output Reports" radio button and "Use ControlTransfers Only" checkbox selected, and received the message "The attempt to write an output report failed."   This was followed by an exception in the method DangerousAddRef.   However the USB analyzer still detected the transmission of 7 bytes on EndPoint 0.

I tried again with the "Exchange Feature Reports" radio button only selected, and received the message "The attempt to write an output report failed."   This was followed by an exception in the method DangerousAddRef.   However the USB analyzer still detected the transmission of 6 bytes on EndPoint 0.  The Feature Report is specified to be 6 bytes long (good).

(A) Why do the Output Reports appear on EndPoint 0 (rather than EndPoint 1 - as specified in the configuration descriptor ?

(B) Is it possible that Windows XP has retained a previous (faulty) report descriptor ?

- Geoff

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: USB Host Software using VB.Net 2010
« Reply #7 on: April 28, 2011, 10:42:16 am »
(B). Yes. Change the Product ID.

Jan

Geoff

  • Member
  • ***
  • Posts: 8
Re: USB Host Software using VB.Net 2010
« Reply #8 on: April 28, 2011, 05:54:30 pm »
Thank you very much !     

After changing the PID, my original VB code can now successfully perform a CreateFile (with dwDesiredAccess of GENERIC_WRITE) and then a WriteFile (with initial byte of the OutputReportBuffer set to "0").   7 bytes were successfully sent via EndPoint 1(which is the correct size and EndPoint for the Output Report).     Excellent.

Obviously, XP remembered an invalid configuration.

Is there any way to clear this undesirable "memory" ?

During this very first enumeration (with new PID), my USB analyzer detected a control request of "Get String Descriptor 238".  My peripheral device STALLed this request, and all subsequent enumerations do not request this string descriptor any more.   Do you know what this request is for ?    [Command sequence: 80 06 EE 03 00 00 12 00  = Get String Descriptor 238, with a length of 18 bytes requested.]

Once again, thank you for your assistance and patience.

-Geoff

Pat Crowe

  • Member
  • ***
  • Posts: 39
Re: USB Host Software using VB.Net 2010
« Reply #9 on: April 28, 2011, 06:18:06 pm »
Your Packet-Master should have displayed the following text in the details pane against that request:

This string request appears to be a non-standard extension to USB, \
introduced by Microsoft, designed to allow Windows only devices. \
It is called the Microsoft OS Descriptor.\

The request only appears once for a given device and can safely be ignored.

Hope this helps.

Geoff

  • Member
  • ***
  • Posts: 8
Re: USB Host Software using VB.Net 2010
« Reply #10 on: April 29, 2011, 03:49:39 am »
Thank you.    I missed the explanation below, and only read the main message:

"
Get String Descriptor 238 (Wrong length)
The device did not reply to this request.  This is an error.
"

The message you listed is displayed below this ... and I agree that I should be able to safely ignore this request.

Pat Crowe

  • Member
  • ***
  • Posts: 39
Re: USB Host Software using VB.Net 2010
« Reply #11 on: April 29, 2011, 05:11:50 am »
Actually, when  said 'ignore', I should have said 'stall', as you don't recognise the request. It's not clear to me whether that's what you are doing

Geoff

  • Member
  • ***
  • Posts: 8
Re: USB Host Software using VB.Net 2010
« Reply #12 on: April 29, 2011, 07:49:49 am »
Yes.  Any unrecognized command is responded to with a "stall" on Endpoint 0.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: USB Host Software using VB.Net 2010
« Reply #13 on: April 29, 2011, 09:55:42 am »
To cause Windows to forget saved descriptors, with the device attached, in Device Manager, right click and click Uninstall. Then remove and reattach the device.

Jan

Geoff

  • Member
  • ***
  • Posts: 8
Re: USB Host Software using VB.Net 2010
« Reply #14 on: April 30, 2011, 04:28:01 am »
Thank you for identifying how to get windows to "forget" saved descriptors.

After "upsetting" my XP Pro SP3 operating system a few times, I found that the step-by-step process is:

(a) Ensure that the HID device is attached to the PC
(b) Open the Device manager
(c) Expand the "Human Interface Devices" group
(d) Identify which "HID-Compliant Device" is the target (check PID and VID in the "details" tab)
(e) Identify which "USB Human Interface Device" is the target (check PID and VID in the "details" tab)
(f) Select the relevant "HID-Compliant Device", right-click and select "uninstall" and then "OK"
(g) The selected "HID-Compliant Device" entry should disappear
(h) Select the relevant "USB Human Interface Device", right-click and select "uninstall" and then "OK"
(i) The selected "USB Human Interface Device" entry should disappear
(j) Disconnect the HID device from the PC

Re-attaching the HID device to the PC causes the initial Windows Popup announcements of Device Name to appear, hence the above process has indeed removed the device from the "saved descriptors".

I found that it was critical to remove the "HID-Compliant Device" first ... before "USB Human Interface Device", otherwise the OS got a bit upset.

-Geoff