Author Topic: How to determine when a HID has completed enumeration and is ready  (Read 13771 times)

Virgil Gomes

  • Member
  • ***
  • Posts: 15
Hi,

I have been having intermittent issues with enumerating my HID device. This is happening during production testing of a product that I’m supporting. During the enumeration process the device is getting removed (not physically) and the enumeration fails with exceptions “Safe handle has been closed, Module:Hid, Method: HidD_SetFeature”.  The “My device removed” is getting displayed in the status window during the enumeration. This is a random failure that may occur 3-5 times in testing 120 units. I am able to simulate the failure by physically removing and connecting the USB cable to the device during the enumeration (Find the Hid).
The test code is based on Jan’s Generic version 4.6 example code in C#. I reviewed Jan’s book “USB Complete 4th edition” on pages 90-95 on enumeration and noticed the host polls  the “GetPortStatus” register enable/disable bit and polls it until the device has enumerated.
I have 2 questions:
1.   Has anyone had the intermittent enumeration issues with the device removing and the exceptions as described above? How did you fix it?
2.   Is there a way to access the “GetPortStatus” via C#? The current test code uses the FindTheHID and MyDeviceDetected in a while loop with a thread sleep of 5 sec  and after 30 attempts fails. I would like to use the GetPortStatus or something similar instead of the while loop to speed up the test and make it more robust.

Greatly appreciate any help and/or recommendations.


Thank you,
Virgil
« Last Edit: July 30, 2012, 10:14:42 am by Virgil Gomes »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: How to determine when a HID has completed enumeration and is ready
« Reply #1 on: July 30, 2012, 01:56:24 pm »
The host won't attempt to send a Feature report until enumeration is complete. Perhaps your device is failing to respond to the Set_Report request.

A protocol analyzer will show what is happening on the bus. If you don't have a protocol analyzer, use whatever debugging tools you have to find out how the device is responding to the requests, data, and events from the host. The first step is to find the line of code in the host program that is triggering the error.

Reading GetPortStatus won't tell you if the device is enumerated.

Jan


Virgil Gomes

  • Member
  • ***
  • Posts: 15
Re: How to determine when a HID has completed enumeration and is ready
« Reply #2 on: July 31, 2012, 04:42:26 pm »
Hi Jan,

Thank you for the response.

This issue is occurring after I do a reset and somewhere while I'm re-enumerating via the FindTheHid. My code is as follows:
1. reset the unit
2. Wait 6 seconds
3. re-enumerate via FindTheHid
4. launch the unit (start communicating)

The exception window "ObjectDisposedException occured" is openning with "Safe handle has been closed" and Troubleshooting tips: "Make sure you have not released a resource before attempting to use it."

Stack Trace:   at XXXX_Test_Program.Hid.HidD_SetFeature(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer, Int32 ReportBufferLength)
   at XXXX_Test_Program.Hid.OutFeatureReport.Write(Byte[] outFeatureReportBuffer, SafeFileHandle hidHandle) in C:\Users\vgomes\Desktop\XXXX Final Test Program\Hid.cs:line


This is the code that this is occurring on (the code is copied from Hid.cs of generic 4.6):  


            internal override Boolean Write( Byte[] outFeatureReportBuffer, SafeFileHandle hidHandle )
            {                
                Boolean success = false;
                
                try
                {
                    //  ***
                    //  API function: HidD_SetFeature
                    
                    //  Purpose: Attempts to send a Feature report to the device.
                    
                    //  Accepts:
                    //  A handle to a HID
                    //  A pointer to a buffer containing the report ID and report
                    //  The size of the buffer.
                    
                    //  Returns: true on success, false on failure.
                    //  ***
                                      
                    success = HidD_SetFeature(hidHandle, outFeatureReportBuffer, outFeatureReportBuffer.Length);
                    
                    Debug.Print( "HidD_SetFeature success = " + success );
                    
                    return success;                    
                }
                catch ( Exception ex )
                {
                    DisplayException( MODULE_NAME, ex );
                    throw ;
                }                
            }            
        }
 
This is the line of code that this is occurring on above:  
success = HidD_SetFeature(hidHandle, outFeatureReportBuffer, outFeatureReportBuffer.Length);


This is a USB trace using the Ellisys USB Tracker:

Type   Title   Device   Endpoint   Direction   Status   Speed   Errors   Size   Data
Container   Class request OUT (0x09)   4   0   Out   OK   FS      8   05 0C 00 99 2B 68 11 29
    Transaction   SETUP   4   0   Out   ACK   FS      8   21 09 00 03 00 00 08 00
    Transaction   OUT   4   0   Out   ACK   FS      8   05 0C 00 99 2B 68 11 29
    Transaction   IN   4   0   In   ACK   FS      0   
Transaction   IN   4   1   In   ACK   FS      64   05 0C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Container   Class request OUT (0x09)   4   0   Out   OK   FS      8   01 07 00 00 00 00 00 00
    Transaction   SETUP   4   0   Out   ACK   FS      8   21 09 00 03 00 00 08 00
    Transaction   OUT   4   0   Out   ACK   FS      8   01 07 00 00 00 00 00 00
    Transaction   IN   4   0   In   ACK   FS      0   
Transaction   IN   4   1   In   ACK   FS      64   01 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Bus state   Reset 755.8 milliseconds                     0   
Bus state   Suspended 111.2 milliseconds                     0   
Bus state   Reset 15.0 milliseconds                     0   
Container   GetDescriptor (Device)   0 (4)   0   In   OK   FS      8   12 01 00 02 00 00 00 08
    Transaction   SETUP   0 (4)   0   Out   ACK   FS      8   80 06 00 01 00 00 40 00
    Transaction   IN   0 (4)   0   In   ACK   FS      8   12 01 00 02 00 00 00 08
    Transaction   OUT   0 (4)   0   Out   ACK   FS      0   
Bus state   Reset 15.0 milliseconds                     0   
Container   SetAddress (4)   0 (4)   0   Out   OK   FS      0   
    Transaction   SETUP   0 (4)   0   Out   ACK   FS      8   00 05 04 00 00 00 00 00
    Transaction   IN   0 (4)   0   In   ACK   FS      0   
Container   GetDescriptor (Device)   4   0   In   OK   FS      18   12 01 00 02 00 00 00 08 1B 0F 29 11 07 03 01 02 03 01
    Transaction   SETUP   4   0   Out   ACK   FS      8   80 06 00 01 00 00 12 00
    Transaction   IN   4   0   In   ACK   FS      8   12 01 00 02 00 00 00 08
    Transaction   IN   4   0   In   ACK   FS      8   1B 0F 29 11 07 03 01 02
    Transaction   IN   4   0   In   ACK   FS      2   03 01
    Transaction   OUT   4   0   Out   ACK   FS      0   
Container   GetDescriptor (Configuration)   4   0   In   OK   FS      34   09 02 22 00 01 01 00 C0 32 09 04 00 00 01 03 00 00 00 09 21 11 01 00 01 22 22 00 07 05 81 03 40 00 01
    Transaction   SETUP   4   0   Out   ACK   FS      8   80 06 00 02 00 00 FF 00
    Transaction   IN   4   0   In   ACK   FS      8   09 02 22 00 01 01 00 C0
    Transaction   IN   4   0   In   ACK   FS      8   32 09 04 00 00 01 03 00
    Transaction   IN   4   0   In   ACK   FS      8   00 00 09 21 11 01 00 01
    Transaction   IN   4   0   In   ACK   FS      8   22 22 00 07 05 81 03 40
    Transaction   IN   4   0   In   ACK   FS      2   00 01
    Transaction   OUT   4   0   Out   ACK   FS      0   
Container   GetDescriptor (String lang IDs)   4   0   In   OK   FS      4   04 03 09 04
    Transaction   SETUP   4   0   Out   ACK   FS      8   80 06 00 03 00 00 FF 00
    Transaction   IN   4   0   In   ACK   FS      4   04 03 09 04
    Transaction   OUT   4   0   Out   ACK   FS      0   
Container   GetDescriptor (Device)   4   0   In   OK   FS      18   12 01 00 02 00 00 00 08 1B 0F 29 11 07 03 01 02 03 01
    Transaction   SETUP   4   0   Out   ACK   FS      8   80 06 00 01 00 00 12 00
    Transaction   IN   4   0   In   ACK   FS      8   12 01 00 02 00 00 00 08
    Transaction   IN   4   0   In   ACK   FS      8   1B 0F 29 11 07 03 01 02
    Transaction   IN   4   0   In   ACK   FS      2   03 01
    Transaction   OUT   4   0   Out   ACK   FS      0   
Container   GetDescriptor (Configuration)   4   0   In   OK   FS      9   09 02 22 00 01 01 00 C0 32
    Transaction   SETUP   4   0   Out   ACK   FS      8   80 06 00 02 00 00 09 00
    Transaction   IN   4   0   In   ACK   FS      8   09 02 22 00 01 01 00 C0
    Transaction   IN   4   0   In   ACK   FS      1   32
    Transaction   OUT   4   0   Out   ACK   FS      0   
Container   GetDescriptor (Configuration)   4   0   In   OK   FS      34   09 02 22 00 01 01 00 C0 32 09 04 00 00 01 03 00 00 00 09 21 11 01 00 01 22 22 00 07 05 81 03 40 00 01
    Transaction   SETUP   4   0   Out   ACK   FS      8   80 06 00 02 00 00 22 00
    Transaction   IN   4   0   In   ACK   FS      8   09 02 22 00 01 01 00 C0
    Transaction   IN   4   0   In   ACK   FS      8   32 09 04 00 00 01 03 00
    Transaction   IN   4   0   In   ACK   FS      8   00 00 09 21 11 01 00 01
    Transaction   IN   4   0   In   ACK   FS      8   22 22 00 07 05 81 03 40
    Transaction   IN   4   0   In   ACK   FS      2   00 01
    Transaction   OUT   4   0   Out   ACK   FS      0   
Container   SetConfiguration (1)   4   0   Out   OK   FS      0   
    Transaction   SETUP   4   0   Out   ACK   FS      8   00 09 01 00 00 00 00 00
    Transaction   IN   4   0   In   ACK   FS      0   
Container   Class request OUT (0x0A)   4   0   Out   OK   FS      0   
    Transaction   SETUP   4   0   Out   ACK   FS      8   21 0A 00 00 00 00 00 00
    Transaction   IN   4   0   In   ACK   FS      0   
Container   GetDescriptor (Class: 0x22)   4   0   In   OK   FS      34   06 A0 FF 09 01 A1 01 09 03 15 00 26 FF 00 75 08 95 40 81 02 09 05 15 00 26 FF 00 75 08 95 08 B1 02 C0
    Transaction   SETUP   4   0   Out   ACK   FS      8   81 06 00 22 00 00 62 00
    Transaction   IN   4   0   In   ACK   FS      8   06 A0 FF 09 01 A1 01 09
    Transaction   IN   4   0   In   ACK   FS      8   03 15 00 26 FF 00 75 08
    Transaction   IN   4   0   In   ACK   FS      8   95 40 81 02 09 05 15 00
    Transaction   IN   4   0   In   ACK   FS      8   26 FF 00 75 08 95 08 B1
    Transaction   IN   4   0   In   ACK   FS      2   02 C0
    Transaction   OUT   4   0   Out   ACK   FS      0   
Container   GetDescriptor (String iSerialNumber)   4   0   In   OK   FS      18   12 03 31 00 30 00 30 00 33 00 38 00 31 00 32 00 30 00
    Transaction   SETUP   4   0   Out   ACK   FS      8   80 06 03 03 09 04 16 00
    Transaction   IN   4   0   In   ACK   FS      8   12 03 31 00 30 00 30 00
    Transaction   IN   4   0   In   ACK   FS      8   33 00 38 00 31 00 32 00
    Transaction   IN   4   0   In   ACK   FS      2   30 00
    Transaction   OUT   4   0   Out   ACK   FS      0   
Container   Class request OUT (0x09)   4   0   Out   OK   FS      8   06 10 00 00 01 00 00 01
    Transaction   SETUP   4   0   Out   ACK   FS      8   21 09 00 03 00 00 08 00
    Transaction   OUT   4   0   Out   NAK   FS      8   06 10 00 00 01 00 00 01
    Transaction   OUT   4   0   Out   ACK   FS      8   06 10 00 00 01 00 00 01
    Transaction   IN   4   0   In   ACK   FS      0   
Transaction   IN   4   1   In   ACK   FS      64   06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
I compared a good run to the above failed run and didn't see anything, but I'm not sure what I should be looking for. Please give me some feedback.

Thank you
« Last Edit: July 31, 2012, 04:45:06 pm by Virgil Gomes »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: How to determine when a HID has completed enumeration and is ready
« Reply #3 on: July 31, 2012, 05:01:23 pm »
What is the purpose of resetting the device?

Do you see the problem if you physically remove and reattach the device?

At HidD_SetFeature, see if hid_handle is valid. (Use a breakpoint.)

Jan

Virgil Gomes

  • Member
  • ***
  • Posts: 15
Re: How to determine when a HID has completed enumeration and is ready
« Reply #4 on: August 01, 2012, 10:39:28 am »
Hi Jan,

The purpose of the reset is to re-enumerate the device after we assign it a new serial number and ensure the new serial number has been detected.

Yes, I can duplicate the problem by physically removing and re-attaching the device during the enumeration.

I looked at the hid_handle at HidD_SetFeatures and the "IsInvalid" = false and the "IsClosed" = true.

Thank you

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: How to determine when a HID has completed enumeration and is ready
« Reply #5 on: August 01, 2012, 02:47:15 pm »
So it's just for manufacturing purposes.

It looks like the handle wasn't closed when the device was removed. You could add code to close the handle if it's already open.

Jan

Virgil Gomes

  • Member
  • ***
  • Posts: 15
Re: How to determine when a HID has completed enumeration and is ready
« Reply #6 on: August 01, 2012, 05:07:01 pm »
Hi Jan,

How did you determine that the handle wasn't closed when the device was removed?

When I looked at the hid_handle at HidD_SetFeatures the "IsClosed" = true which I thought the it was closed.

Thank you

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: How to determine when a HID has completed enumeration and is ready
« Reply #7 on: August 01, 2012, 05:48:44 pm »
The application has to close the handle on removal so it can reopen it on attachment.

Jan

Virgil Gomes

  • Member
  • ***
  • Posts: 15
Re: How to determine when a HID has completed enumeration and is ready
« Reply #8 on: August 03, 2012, 09:02:09 am »
Hi Jan,

I will check the code to ensure it is closing the handle when removing the device.

Thank you,

Virgil Gomes

  • Member
  • ***
  • Posts: 15
Re: How to determine when a HID has completed enumeration and is ready
« Reply #9 on: August 03, 2012, 09:15:05 am »
Hi Jan,


Getting back to my original question:

How can the host software (for example your Generic C# test code)  determine when a HID has completed enumeration and is ready after a reset to the HID is sent? Is there anything that the test code can interigate in either the Hid device or Host OS?

The reason I'm asking is that after I do a reset the unit starts to enumerate. In my test code after I send the reset command to the HID, I wait 6 seconds and then use the FindTheHid to determine if the device is ready. I would like to make the test code more efficent and not wait a period of time but rather poll  something like the GetPortStatus to see if the HID device is enabled and ready.

Thank you

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: How to determine when a HID has completed enumeration and is ready
« Reply #10 on: August 03, 2012, 02:43:46 pm »
When a device attaches, the OnDeviceChange routine executes. You could add code there to call FindTheHid.

Jan