PORTS Forum
Ports and Interfaces => USB => Topic started by: Geoff 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.
-
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
-
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.
-
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
-
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 ?
-
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
-
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
-
(B). Yes. Change the Product ID.
Jan
-
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
-
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.
-
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.
-
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
-
Yes. Any unrecognized command is responded to with a "stall" on Endpoint 0.
-
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
-
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
-
Thanks for the added info!
Jan