08-05-2008 10:04 AM - edited 08-05-2008 10:04 AM
In the first part of my USB nugget(s) I showed some ways to get started with Interrupt transfers using a mouse as an example. Today I'm going to briefly touch on a second type of USB transfer, the Control transfer.
As with the first nugget, the USB 2.0 specification is a must-read (especially chapter 9) when attempting to understand USB communication. The specification can be downloaded HERE. You will also need to install (on Windows at least) a VISA RAW driver for whatever device you wish to use. A guide as to how to enable VISA RAW access to a device can be found HERE.
There are four types of transfer in the USB 2.0 Specification (Paragraph 5.4, Page 36 of the USB spec). Each different sort of transfer has different characteristics in an effort to allow for very different types of devices.
Transfer Type |
Characteristics |
Used for |
Control |
Up to 15.8MB/s Every Device must support these Used for Enumeration Extendable : Custom functions |
Everything |
Interrupt |
Up to 49MB/s Asynchronous Guaranteed low latency Guaranteed throughput |
HID (mouse, Keyboard) |
Isochronous |
Up to 49MB/s High speed No Error-correction Guaranteed bandwidth |
Audo Video |
Bulk |
Up to 53MB/s High speed (on unused bus) Error Correction Low priority on bus |
Test & Measurement Mass Storage |
ALL USB devices MUST support control transfers as this is the method used during enumeration on the bus. A host controller will retrieve vendor ID, Device ID and a host of other information via Control transfers during enumeration. This data is retrievable via a group of standard requests. All devices, irrespective of their current state are required to respond to all of these standard requests. As such, they are ideal for testing whether communication is working or not.
I will focus only on non-compound devices in this nugget. Compound devices are devices which have more than one interface. These could be (in the example of a USB-music player) “HID” interface for any controls and “Audio” interface for music streaming. The device could additionally have a “Mass Storage” Interface for easy data copying. I have not (yet) delved into compound devices so I am unable to offer any useful information on that front.
I will also highlight how USB Control transfers look when using a USB Logger and how many devices use Control transfers for their own communication (with a simple example).
08-05-2008 10:04 AM
For USB Logging, I personally have found the (non-free) “Device Monitoring Studio” (which seems to have been renamed to “USB Monitor”) to be of great help. Other, free programs are available such as “Snoopy Pro”. These programs sit between the Operating system and the device driver and records all communication.
In the examples I will work through, I had the luxury of having a pre-existing working driver for my target device which I could already use in LabVIEW. This enabled me to use a USB logging software to see exactly what was being sent to the device and what was coming back. Since I could already control the device via LabVIEW (Via DLL) I was relatively quickly able to pin-point which commands were tied to which functions.
A quick mention to the “why” of this action if I already had a driver. Apart from “because I could”, I wanted the software to run under Linux. The supplied DLL wouldn't do that..
A sample log of a basic communication may look like the example shown below. Entries 000050 and 000051 belong to a standard request defined within the USB Specification used to get the Device Descriptor (Table 9-3 on Page 250). The second pair (000052 and 000053) are custom device-specific requests which were the target of my investigations. All data needed to implement this call through VISA is presented in an easy-to-understand form.
000050: Get Descriptor Request (DOWN), 09.11.2007 14:35:32.156 +33.156
Descriptor Type: Device
Descriptor Index: 0x0
Transfer Buffer Size: 0x12 bytes
000051: Control Transfer (UP), 09.11.2007 14:35:36.781 +4.625. Status: 0x00000000
Pipe Handle: 0x88df4020
12 01 00 01 00 00 00 40 61 06 00 29 00 00 00 00 .......@a..)....
00 01 ..
Setup Packet
80 06 00 01 00 00 12 00 .......
Recipient: Device
Request Type: Standard
Direction: Device->Host
Request: 0x6 (GET_DESCRIPTOR)
Value: 0x100
Index: 0x0
Length: 0x12
000052: Vendor-Specific Request (DOWN), 09.11.2007 14:35:36.781 +0.0
Destination: Other
Reserved Bits: 0
Request: 0x4
Value: 0x1c8
Get 0x8 bytes from the device
000053: Control Transfer (UP), 09.11.2007 14:35:36.781 +0.0. Status: 0x00000000
Pipe Handle: 0x88df4020
62 31 30 34 37 31 30 32 b1047102
Setup Packet
C3 04 C8 01 00 00 08 00 Ã.È.....
Recipient: Other
Request Type: Vendor
Direction: Device->Host
Request: 0x4 (Unknown)
Value: 0x1c8
Index: 0x0
Length: 0x8
The data packets (in this case Device to Host) are shown in italicised bold font. The setup Packet is not of interest for us at the moment as VISA takes care of this when we give the correct transmission parameters. The USB transmission parameters used to initiate this transfer is shown at the bottom of each entry (Recipient, Request type and so on). These seven parameters are detailed enough for us to be able to implement the functionality we require.
-Note-
I personally got stuck at this point for quite a while trying to implement this in LabVIEW. The information IS all in the USB specification, but it required a lot of trial and error on my part to get it working. I want to help others avoid thie trial and error part by sharing with the community how I got this done.
-End Note-.
08-05-2008 10:16 AM - edited 08-05-2008 10:18 AM
The key to understanding what these seven values are is listed in Table 9-2 of Paragraph 9.3 of the USB Specification document, reproduced here (hoping I don't get sued for Copyright infringement).
Examining the USB Logger output and Table 9-2 we can find all seven of our USB parameters. Three of the parameters are actually bitmapped into a single value “bmRequestType”. The Direction of the request (Command to device or request from device), What type of request it is (Standard, Class, Vendor) and the intended recipient of the packet (Device, Interface, Endpoint or Other). The other four parameters are passed individually.
The second entry in the table is the “bRequest” entry. Table 9-3 of the USB Specification lists several standard request types. Tables 9_4 and 9_5 are also required in order to fully understand what is going on here.
Table 9_4 lists the Byte values for each of the standard bRequest types. In the case of the bRequest Types “GET_DESCRIPTOR” or “SET_DESCRIPTOR” an additional value is required as to what TYPE of Descriptor is involved. These values are then listed in Table 9_5.
We now have enough Information to understand what the request listed in the USB log above is actually for.
The first three entries;
Recipient: Device
Request Type: Standard
Direction: Device->Host
tell us that we are sending a data packet to the device, making a request for information from the device and that the request is a Standard request.
The following line
Request: 0x6 (GET_DESCRIPTOR)
tells us that the standard Request being executed is a request for a Descriptor. Looking at the entry in Table 9_3 for the Request “GET_DESCRIPTOR” tells us what the last three values mean:
Value: 0x100
Index: 0x0
Length: 0x12
Value represents “Descriptor Type and Descriptor Index”. The first 8 Bytes correspond to the value 1, which from Table 9_5 tells us is the DEVICE Descriptor. The second Byte is zero, telling us that we want the Descriptor at index zero (Some Devices have multiple instances of a certain type of descriptor).
Index represents “Zero or Language ID”. Since this value is zero, we are requesting the default descriptor. Since Descriptors may contain text which is language-dependent, a device can store many different descriptors for different languages if required.
Length represents the “Descriptor Length”. Although we are required to enter a value here, it can often happen that the returned descriptor is longer than the requested length. Since the length of the actual descriptor is contained within the header for the actual descriptor (18 Bytes, 0x12 in Hexadecimal Paragraph 9.6.1, Table 9_8 on Page 261 and onwards of the USB Specification), an initial request for 18 Bytes is normal which can then be followed up with a request for the corrent length of descriptor.
This is jsut a single example of a command which according to the USB specification EVERY USB Device should respond to. As such it can be used to test any early attempts to get USB communication up and running.
I have also implemented a couple of simple enums for the values of the Standard Request Codes and the Descriptor Types as outlined in Tables 9_4 and 9_5.
Now that we know what the various entries in our USB Log are for, we can move over to implementing some communication in LabVIEW.
08-05-2008 10:20 AM - edited 08-05-2008 10:23 AM
If we now look at the Connection pane of the respective VISA function we see all these values present also.
- Note - I was initially very confused with the nomenclature “Control IN” and “Control OUT”. I thought it counter-intuitive that the function for sending requests to a device is called “VISA USB Control In” and not “Out”. An example from NI finally sorted me out (Which I unfortunately cannot locate at the moment).
- End of Note -
Assuming we have implemented our RAW driver as outlined in the NI tutorial above, we should be able to choose our device from a VISA control. In the examples shown below, I have connected a second mouse (Microsoft 2-Button mouse with scroll wheel) to my PC and have run the Device driver wizard for VISA. Once this is completed, the device is visible whenever I use a VISA control set to USB devices.
Once we have done this, any devices configured for USB RAW communication via the VISA Driver wizard should be visible.
The first device shown here is a USB Spectrometer I have been communicating with over USB, the second is the MS-Mouse (Vendor ID 0x045E, Product ID 0x0084).
We can then use the VISA Open just like any other VISA resource to open a handle to the device.
Now all we need to do is wire up our request to the device for a device descriptor and we're basically done.
The picture below shows the values needed for a simple device descriptor request using the Vis and controls I have implemented.
We
can see that we are doing basically the very same request as
originally recorded using the USB Logger program mentioned at the
beginning.
As a reminder:
Recipient: Device
Request Type: Standard
Direction: Device->Host
Request: 0x6 (GET_DESCRIPTOR)
Value: 0x100
Index: 0x0
Length: 0x12
The “Index” value is not shown because the default value for the “VISA USB Control In” VI is already zero.
The result of this communication should now be available at the output terminal of our VISA Control In VI. In order to format this into something we might understand, the following code is used:
The Constant “USB _bDescriptor Type 1” is a Typedef representing the data structure of the Device Descriptor as outlined in Table 9_8 of Paragraph 9.6.1 of the USB Specification. The first two Bytes are ignored as they contain information not required by the conversion (Descriptor size and bDescriptor Type). We could incorporate these two Bytes into our Typedef and do away with this step.
In order to convert the received 16-bit values into a LV-Conform format, we perform a Byte Swap on the values “bcdUSB”, idVendor” and “idProduct”.
In the case of the MS Mouse, we get a data structure as follows:
We see the Vendor ID (0x045E) and the Product ID (0x0084) are contained within the Device Descriptor. This is actually the method used by the OS to determine what has actually been attached to the computer.
We also see some other information such as max Packet size (8).
Using this nugget, we have enough information to request other device information also, such as the “Standard Configuration Decsriptor” from the device. This is already implemented in one of the Vis attached.
The functionality highlighted in the USB Logger information at the beginning of this nugget can now easily be implemented in LabVIEW. The device-specific part was a request to a miniature USB spectrometer to retrieve the serial number of the unit. Using the USB Logger (And some good guess-work to work out the format of transferred data) I have been able to implement a pure G (USB via VISA) spectrometer driver for my applications. The program works under Windows and Linux. Should work under Mac too, but I haven't got a mac for testing.
This nugget has truly only scratches the surface of USB Control transfers. For those of you willing to go through the hardships of getting acquainted with USB, I hope the information and Vis posted here help reduce the probability of hair loss in the process.
Shane.
08-05-2008 10:25 AM - edited 08-05-2008 10:35 AM
08-05-2008 01:12 PM
You almost make me WANT to do USB communication.
At least I know that when I do, I'll have where to start.
08-05-2008 02:24 PM
This is excellent timing...
I am starting a USB project.. Hope it's okay to ask "general" questions in this thread. I'll start new thread for specific ones..
Great Nugget! Many Thanks!
R
08-06-2008 02:31 AM - edited 08-06-2008 02:36 AM
08-06-2008 05:52 AM
Thanks Shane!
I will not be able to give this serious read today since it requires more than the 9 minutes I have available today.
Ben
08-06-2008 06:40 AM