Posts

Arduino USB Host – USB Descriptors.

Get device descriptor trace

Get device descriptor trace

I finished porting USB transfers from PIC C to Arduino C++. There is now a USB class in the repository. Two main types of USB transfers – control and bulk, are implemented. If you want to know more about USB transfer mechanics, take a look at this article. The code was written to work on Microchip PIC, however, the Arduino code is almost identical.

Since we now have tools to talk to USB device, let’s start using them by looking at USB descriptors. In order for sketches from this article to work you need to copy current repository contents ( *.cpp and *.h files ) to a sub directory in your Arduino hardware libraries directory. In addition, don’t forget to supply 5V to Vbus and connect a USB device, such as flash drive or mouse to USB connector of a breakout board.

First sketch demonstrates access to device descriptor. Device descriptor is the first descriptor that the host retrieves from the device during enumeration. The information which host needs is device endpoint zero maximum packet size. In this example, maximum packet size is already set by a function in USB class, called “Task”. In addition to maximum packet size device descriptor contains other information, used during device configuration.

/* MAX3421E USB Host controller get device descriptor */
#include <spi.h>
#include <max3421e.h>
#include <usb.h>
 
void setup();
void loop();
 
MAX3421E Max;
USB Usb;
 
void setup()
{
  byte tmpdata = 0;
  Serial.begin( 9600 );
  Serial.println("Start");
  Max.powerOn();
  delay( 200 );
}
 
void loop()
{
  byte rcode;
  Max.Task();
  Usb.Task();
  if( Usb.getUsbTaskState() >= 0x80 ) {  //state configuring or higher
    rcode = getdevdescr( 1 );                    //hardcoded device address
    if( rcode ) {
      Serial.print("\r\nRequest error. Error code:\t");
      print_hex( rcode, 8 );
    }
    while( 1 );                          //stop
  }
}
 
byte getdevdescr( byte addr )
{
  USB_DEVICE_DESCRIPTOR buf;
  byte rcode;
  rcode = Usb.getDevDescr( addr, 0, 0x12, ( char *)&buf );
  if( rcode ) {
    return( rcode );
  }
  Serial.println("Device descriptor: ");
  Serial.print("Descriptor Length:\t");
  print_hex( buf.bLength, 8 );
  Serial.print("\r\nDescriptor type:\t");
  print_hex( buf.bDescriptorType, 8 );
  Serial.print("\r\nUSB version:\t");
  print_hex( buf.bcdUSB, 16 );
  Serial.print("\r\nDevice class:\t");
  print_hex( buf.bDeviceClass, 8 );
  Serial.print("\r\nDevice Subclass:\t");
  print_hex( buf.bDeviceSubClass, 8 );
  Serial.print("\r\nDevice Protocol:\t");
  print_hex( buf.bDeviceProtocol, 8 );
  Serial.print("\r\nMax.packet size:\t");
  print_hex( buf.bMaxPacketSize0, 8 );
  Serial.print("\r\nVendor  ID:\t");
  print_hex( buf.idVendor, 16 );
  Serial.print("\r\nProduct ID:\t");
  print_hex( buf.idProduct, 16 );
  Serial.print("\r\nRevision ID:\t");
  print_hex( buf.bcdDevice, 16 );
  Serial.print("\r\nMfg.string index:\t");
  print_hex( buf.iManufacturer, 8 );
  Serial.print("\r\nProd.string index:\t");
  print_hex( buf.iProduct, 8 );
  Serial.print("\r\nSerial number index:\t");
  print_hex( buf.iSerialNumber, 8 );
  Serial.print("\r\nNumber of conf.:\t");
  print_hex( buf.bNumConfigurations, 8 );
  return( 0 );
}
 
/* prints hex numbers with leading zeroes */
// copyright, Peter H Anderson, Baltimore, MD, Nov, '07
// source: http://www.phanderson.com/arduino/arduino_display.html
void print_hex(int v, int num_places)
{
  int mask=0, n, num_nibbles, digit;
 
  for (n=1; n<=num_places; n++)
  {
    mask = (mask << 1) | 0x0001;
  }
  v = v & mask; // truncate v to specified number of places
 
  num_nibbles = num_places / 4;
  if ((num_places % 4) != 0)
  {
    ++num_nibbles;
  }
 
  do
  {
    digit = ((v >> (num_nibbles-1) * 4)) & 0x0f;
    Serial.print(digit, HEX);
  }
  while(--num_nibbles);
 
}

Load the sketch, compile, and run. Don’t forget to connect a device, otherwise program will print “Start” and pause waiting for the device to be connected. If everything is OK, you will see output similar to one below.

Start
Device descriptor:
Descriptor Length:      12
Descriptor type:        01
USB version:            0100
Device class:           00
Device Subclass:        00
Device Protocol:        00
Max.packet size:        40
Vendor  ID:             0CF2
Product ID:             6220
Revision ID:            0100
Mfg.string index:       01
Prod.string index:      02
Serial number index:    04
Number of conf.:        01

Let’s take a look. The first line shows descriptor size – 18 bytes ( 12 Hex ). Next line shows descriptor type (01 – device descriptor). USB version shows 0100, that’s version 1.0, the very first one. Even though USB version 3.0 is here, many low speed devices are still manufactured. I have seen web cameras compliant to USB version 1.1 and low-speed mice and keyboards. Device used in this example is pretty new flash drive, by the way.

Device class, subclass, and protocol are set to zero. This usually means that device is supported as a class and class properties are defined on interface level. Maximum packet size is 64 bytes ( 40 hex ). Vendor ID and Product ID form unique device identifier.

Strings are human-readable descriptors. Device descriptor contains index values to some of the strings. If index of a string is zero, the corresponding string is not implemented. Also, since string descriptors are optional and, with very few exceptions, are not used during normal operation, many manufacturers implement strings incorrectly.

Last byte shows number of configurations supported by the device.

Next sketch shows how to get string descriptor. Unlike device descriptor, string descriptor length is variable. In addition, strings can be coded in several languages. Therefore, the sequence of actions to get a string is more complicated than one used to get device descriptor. First, we find out length of string descriptor with index zero, which contains Language IDs. Then, we ask for the same descriptor again, this time using the correct length. Next step is to extract first Language ID. After that we find out the length of the descriptor that we want, and finally get the whole descriptor and print it. Take a look at the code:

/* MAX3421E USB Host controller get string descriptor */
#include <spi.h>
#include <max3421e.h>
#include <usb.h>
 
#define LOBYTE(x) ((char*)(&(x)))[0]
#define HIBYTE(x) ((char*)(&(x)))[1]
 
void setup();
void loop();
 
MAX3421E Max;
USB Usb;
 
void setup()
{
  byte tmpdata = 0;
  Serial.begin( 9600 );
  Serial.println("Start");
  Max.powerOn();
  delay( 200 );
}
 
void loop()
{
  byte rcode;
  Max.Task();
  Usb.Task();
  if( Usb.getUsbTaskState() >= 0x80 ) {  //state configuring or higher
    rcode = getstrdescr( 1, 1 );                 //get string descriptor
    if( rcode ) {
      Serial.println( rcode, HEX );
    }
    while( 1 );                          //stop
  }
}
 
byte getstrdescr( byte addr, byte idx )
{
  char buf[ 66 ];
  byte rcode;
  byte length;
  byte i;
  unsigned int langid;
  rcode = Usb.getStrDescr( addr, 0, 1, 0, 0, buf );  //get language table length
  if( rcode ) {
    Serial.println("Error retrieving LangID table length");
    return( rcode );
  }
  length = buf[ 0 ];      //length is the first byte
  rcode = Usb.getStrDescr( addr, 0, length, 0, 0, buf );  //get language table
  if( rcode ) {
    Serial.println("Error retrieving LangID table");
    return( rcode );
  }
  HIBYTE( langid ) = buf[ 3 ];                            //get first langid
  LOBYTE( langid ) = buf[ 2 ];
  rcode = Usb.getStrDescr( addr, 0, 1, idx, langid, buf );
  if( rcode ) {
    Serial.println("Error retrieving string length");
    return( rcode );
  }
  length = buf[ 0 ];
  rcode = Usb.getStrDescr( addr, 0, length, idx, langid, buf );
  if( rcode ) {
    Serial.println("Error retrieving string");
    return( rcode );
  }
  for( i = 2; i < length; i+=2 ) {
    Serial.print( buf[ i ] );
  }
  return( rcode );
}

The “getstrdescr” function takes string index as a second argument. It is set to 1 in the code, because almost any USB device has this string defined. However, if you want to see other strings of your device, just change the index number in “getstrdescr” call from the loop(), re-complile the sketch and run it.

The last sketch in this article demonstrates getting configuration descriptor. Configuration descriptor contains a wealth of information about the peripheral configuration, such as interfaces, their power consumption, endpoints and their maximum packet sizes, polling intervals, etc. The structure of configuration descriptor is even more complicated. Quoting USB 2.0 specification, “When the host requests the configuration descriptor, all related interface and endpoint descriptors are returned”. It means that not only length of the descriptor is variable, but data structure needs to be analyzed during retrieval since we don’t know in advance which descriptors would follow configuration.

In order to operate an USB device, configuration descriptor and subsequent descriptors has to be parsed. We need configuration value to switch USB device to the running state (called “configured” in USB spec), endpoint addresses, directions, and maximum packet sizes, as well as values from class-specific descriptors, if any. The sketch determines configuration length, retrieves it, an then goes through the buffer, printing configuration, interface, endpoint, or unknown descriptors as it encounters them.

/* MAX3421E USB Host controller get configuration descriptor */
#include <spi.h>
#include <max3421e.h>
#include <usb.h>
 
#define LOBYTE(x) ((char*)(&(x)))[0]
#define HIBYTE(x) ((char*)(&(x)))[1]
#define BUFSIZE 256    //buffer size
 
void setup();
void loop();
 
MAX3421E Max;
USB Usb;
 
void setup()
{
  byte tmpdata = 0;
  Serial.begin( 9600 );
  Serial.println("Start");
  Max.powerOn();
  delay( 200 );
}
 
void loop()
{
  byte rcode;
  Max.Task();
  Usb.Task();
  if( Usb.getUsbTaskState() >= 0x80 ) {  //state configuring or higher
    rcode = getconfdescr( 1, 0 );                 //get configuration descriptor
    if( rcode ) {
      Serial.println( rcode, HEX );
    }
    while( 1 );                          //stop
  }
}
 
byte getconfdescr( byte addr, byte conf )
{
  char buf[ BUFSIZE ];
  char* buf_ptr = buf;
  byte rcode;
  byte descr_length;
  byte descr_type;
  unsigned int total_length;
  rcode = Usb.getConfDescr( addr, 0, 4, conf, buf );  //get total length
  LOBYTE( total_length ) = buf[ 2 ];
  HIBYTE( total_length ) = buf[ 3 ];
  if( total_length > 256 ) {    //check if total length is larger than buffer
    Serial.println("Total length truncated to 256 bytes");
    total_length = 256;
  }
  rcode = Usb.getConfDescr( addr, 0, total_length, conf, buf ); //get the whole descriptor
  while( buf_ptr < buf + total_length ) {  //parsing descriptors
    descr_length = *( buf_ptr );
    descr_type = *( buf_ptr + 1 );
    switch( descr_type ) {
      case( USB_DESCRIPTOR_CONFIGURATION ):
        printconfdescr( buf_ptr );
        break;
      case( USB_DESCRIPTOR_INTERFACE ):
        printintfdescr( buf_ptr );
        break;
      case( USB_DESCRIPTOR_ENDPOINT ):
        printepdescr( buf_ptr );
        break;
      default:
        printunkdescr( buf_ptr );
        break;
        }//switch( descr_type
    buf_ptr = ( buf_ptr + descr_length );    //advance buffer pointer
  }//while( buf_ptr <=...
  return( 0 );
}
/* prints hex numbers with leading zeroes */
// copyright, Peter H Anderson, Baltimore, MD, Nov, '07
// source: http://www.phanderson.com/arduino/arduino_display.html
void print_hex(int v, int num_places)
{
  int mask=0, n, num_nibbles, digit;
 
  for (n=1; n<=num_places; n++) {
    mask = (mask << 1) | 0x0001;
  }
  v = v & mask; // truncate v to specified number of places
 
  num_nibbles = num_places / 4;
  if ((num_places % 4) != 0) {
    ++num_nibbles;
  }
  do {
    digit = ((v >> (num_nibbles-1) * 4)) & 0x0f;
    Serial.print(digit, HEX);
  }
  while(--num_nibbles);
}
/* function to print configuration descriptor */
void printconfdescr( char* descr_ptr )
{
 USB_CONFIGURATION_DESCRIPTOR* conf_ptr = ( USB_CONFIGURATION_DESCRIPTOR* )descr_ptr;
  Serial.println("Configuration descriptor:");
  Serial.print("Total length:\t");
  print_hex( conf_ptr->wTotalLength, 16 );
  Serial.print("\r\nNum.intf:\t\t");
  print_hex( conf_ptr->bNumInterfaces, 8 );
  Serial.print("\r\nConf.value:\t");
  print_hex( conf_ptr->bConfigurationValue, 8 );
  Serial.print("\r\nConf.string:\t");
  print_hex( conf_ptr->iConfiguration, 8 );
  Serial.print("\r\nAttr.:\t\t");
  print_hex( conf_ptr->bmAttributes, 8 );
  Serial.print("\r\nMax.pwr:\t\t");
  print_hex( conf_ptr->bMaxPower, 8 );
  return;
}
/* function to print interface descriptor */
void printintfdescr( char* descr_ptr )
{
 USB_INTERFACE_DESCRIPTOR* intf_ptr = ( USB_INTERFACE_DESCRIPTOR* )descr_ptr;
  Serial.println("\r\nInterface descriptor:");
  Serial.print("Intf.number:\t");
  print_hex( intf_ptr->bInterfaceNumber, 8 );
  Serial.print("\r\nAlt.:\t\t");
  print_hex( intf_ptr->bAlternateSetting, 8 );
  Serial.print("\r\nEndpoints:\t\t");
  print_hex( intf_ptr->bNumEndpoints, 8 );
  Serial.print("\r\nClass:\t\t");
  print_hex( intf_ptr->bInterfaceClass, 8 );
  Serial.print("\r\nSubclass:\t\t");
  print_hex( intf_ptr->bInterfaceSubClass, 8 );
  Serial.print("\r\nProtocol:\t\t");
  print_hex( intf_ptr->bInterfaceProtocol, 8 );
  Serial.print("\r\nIntf.string:\t");
  print_hex( intf_ptr->iInterface, 8 );
  return;
}
/* function to print endpoint descriptor */
void printepdescr( char* descr_ptr )
{
 USB_ENDPOINT_DESCRIPTOR* ep_ptr = ( USB_ENDPOINT_DESCRIPTOR* )descr_ptr;
  Serial.println("\r\nEndpoint descriptor:");
  Serial.print("Endpoint address:\t");
  print_hex( ep_ptr->bEndpointAddress, 8 );
  Serial.print("\r\nAttr.:\t\t");
  print_hex( ep_ptr->bmAttributes, 8 );
  Serial.print("\r\nMax.pkt size:\t");
  print_hex( ep_ptr->wMaxPacketSize, 16 );
  Serial.print("\r\nPolling interval:\t");
  print_hex( ep_ptr->bInterval, 8 );
  return;
}
/*function to print unknown descriptor */
void printunkdescr( char* descr_ptr )
{
  byte length = *descr_ptr;
  byte i;
  Serial.println("\r\nUnknown descriptor:");
  Serial. print("Length:\t\t");
  print_hex( *descr_ptr, 8 );
  Serial.print("\r\nType:\t\t");
  print_hex( *(descr_ptr + 1 ), 8 );
  Serial.print("\r\nContents:\t");
  descr_ptr += 2;
  for( i = 0; i < length; i++ ) {
    print_hex( *descr_ptr, 8 );
    descr_ptr++;
  }
}

Let’s look at the output. First example shows configuration of USB flash drive. The configuration is very simple – one interface, two bulk endpoints (in addition to endpoint zero). We can see that total length of the configuration is 32 bytes (20 hex ), has one interface, the configuration value to use in “Set configuration” request to activate this configuration is “1”, string is not defined, all attributes are zero (by spec, MSB of attributes field is always one and is not an attribute ), and power consumption is 100mA.

Start
Configuration descriptor:
Total length:       0020
Num.intf:           01
Conf.value:         01
Conf.string:        00
Attr.:              80
Max.pwr:            32

Interface descriptor:
Intf.number:        00
Alt.:               00
Endpoints:          02
Class:              08
Subclass:           06
Protocol:           50
Intf.string:        00

Endpoint descriptor:
Endpoint address:   81
Attr.:              02
Max.pkt size:       0040
Polling interval:   00

Endpoint descriptor:
Endpoint address:   01
Attr.:              02
Max.pkt size:       0040
Polling interval:   00

Interface descriptor shows interface number and two endpoints. Class, subclass, and protocol combination states that this device supports so-called “Mass-storage bulk-only transport” protocol – the most popular way to communicate with USB flash drives. Endpoints show address (which is called number in USB spec ) and direction (81 means “number 01, direction IN”), attributes (02 means “bulk”), maximum packet size 64 bytes, and polling interval zero, which, by the way, doesn’t make sense for bulk endpoints anyway.

Next example shows configuration of USB keyboard. This is a ptetty modern keyboard with extra buttons for web browsing and media player control. We can see two interfaces and two unknown descriptors. They are HID descriptors – per spec, any class-specific descriptors must follow interface descriptor. The first interface shows class 03 (HID), subclass 01 (keyboard), and protocol 01 (boot protocol). Boot protocol is a simplified protocol, which allows using USB keyboards during PC boot.

Second interface is just a plain HID interface. To use it, application needs to retrieve and parse HID reports for the interface.

Start
Configuration descriptor:
Total length:       003B
Num.intf:           02
Conf.value:         01
Conf.string:        03
Attr.:              A0
Max.pwr:            32

Interface descriptor:
Intf.number:        00
Alt.:               00
Endpoints:          01
Class:              03
Subclass:           01
Protocol:           01
Intf.string:        00

Unknown descriptor:
Length:             09
Type:               21
Contents:           10010001223E000705

Endpoint descriptor:
Endpoint address:   81
Attr.:              03
Max.pkt size:       0008
Polling interval:   0A

Interface descriptor:
Intf.number:        01
Alt.:               00
Endpoints:          01
Class:              03
Subclass:           00
Protocol:           00
Intf.string:        00

Unknown descriptor:
Length:             09
Type:               21
Contents:           1001000122AB000705

Endpoint descriptor:
Endpoint address:   82
Attr.:              03
Max.pkt size:       0008
Polling interval:   0A

The last example is taken from my favorite no-name USB Bluetooth device. I like it for the implementation – it is phenomenally buggy. Strings are messy, descriptors don’t make sense (look at max.power, for example, or the last interface with no endpoints), plus, the configuration is quite long. It goes without explanation, just take a look to get an idea of how complex USB devices can really be.

Start
Configuration descriptor:
Total length:       00BA
Num.intf:           03
Conf.value:         01
Conf.string:        00
Attr.:              C0
Max.pwr:            00

Interface descriptor:
Intf.number:        00
Alt.:               00
Endpoints:          03
Class:              E0
Subclass:           01
Protocol:           01
Intf.string:        00

Endpoint descriptor:
Endpoint address:   81
Attr.:              03
Max.pkt size:       0010
Polling interval:   01

Endpoint descriptor:
Endpoint address:   02
Attr.:              02
Max.pkt size:       0040
Polling interval:   01

Endpoint descriptor:
Endpoint address:   82
Attr.:              02
Max.pkt size:       0040
Polling interval:   01

Interface descriptor:
Intf.number:        01
Alt.:               00
Endpoints:          02
Class:              E0
Subclass:           01
Protocol:           01
Intf.string:        00

Endpoint descriptor:
Endpoint address:   03
Attr.:              01
Max.pkt size:       0000
Polling interval:   01

Endpoint descriptor:
Endpoint address:   83
Attr.:              01
Max.pkt size:       0000
Polling interval:   01

Interface descriptor:
Intf.number:        01
Alt.:               01
Endpoints:          02
Class:              E0
Subclass:           01
Protocol:           01
Intf.string:        00

Endpoint descriptor:
Endpoint address:   03
Attr.:              01
Max.pkt size:       0009
Polling interval:   01

Endpoint descriptor:
Endpoint address:   83
Attr.:              01
Max.pkt size:       0009
Polling interval:   01

Interface descriptor:
Intf.number:        01
Alt.:               02
Endpoints:          02
Class:              E0
Subclass:           01
Protocol:           01
Intf.string:        00

Endpoint descriptor:
Endpoint address:   03
Attr.:              01
Max.pkt size:       0011
Polling interval:   01

Endpoint descriptor:
Endpoint address:   83
Attr.:              01
Max.pkt size:       0011
Polling interval:   01

Interface descriptor:
Intf.number:        01
Alt.:               03
Endpoints:          02
Class:              E0
Subclass:           01
Protocol:           01
Intf.string:        00

Endpoint descriptor:
Endpoint address:   03
Attr.:              01
Max.pkt size:       0019
Polling interval:   01

Endpoint descriptor:
Endpoint address:   83
Attr.:              01
Max.pkt size:       0019
Polling interval:   01

Interface descriptor:
Intf.number:        01
Alt.:               04
Endpoints:          02
Class:              E0
Subclass:           01
Protocol:           01
Intf.string:        00

Endpoint descriptor:
Endpoint address:   03
Attr.:              01
Max.pkt size:       0021
Polling interval:   01

Endpoint descriptor:
Endpoint address:   83
Attr.:              01
Max.pkt size:       0021
Polling interval:   01

Interface descriptor:
Intf.number:        01
Alt.:               05
Endpoints:          02
Class:              E0
Subclass:           01
Protocol:           01
Intf.string:        00

Endpoint descriptor:
Endpoint address:   03
Attr.:              01
Max.pkt size:       0031
Polling interval:   01

Endpoint descriptor:
Endpoint address:   83
Attr.:              01
Max.pkt size:       0031
Polling interval:   01

Interface descriptor:
Intf.number:        02
Alt.:               00
Endpoints:          00
Class:              FE
Subclass:           01
Protocol:           00
Intf.string:        00

In the next article, I will show how to use “Set” requests, as well as how to actually use USB device for something more interesting than looking at its descriptors. Stay tuned!

Oleg.

40 comments to Arduino USB Host – USB Descriptors.

  • Mike

    Hi Oleg,

    I’ve built an arduino project that uses a GPRS shield to send SMS’s. I now need to make a dozen similar modules and am trying to save money. Each GPRS shield costs about $100 or more, but I can get a USB GPRS dongle for less than $10. I’d like to use a arduino USB host shield to connect the arduino straight to the dongle. Before I invest too much time and energy into this, can you give me some idea if what I’m trying to is feasable, and if so how difficult would it be? The USB GPRS dongle I’m using is a HUAWEI E1750, I only need very basic functionality, just enough to send SMS’s only.

    Thanks for your help

    Mike

    • Hi Mike,

      From what I learned so far, GPRS is not that difficult to implement. The biggest issue would be getting programming documentation for your module or reverse engineer control commands if unable to get docs.

      I have USB GPRS code on my todo list also, don’t know when I’ll be able to start, though.

      Good luck with your project!

      Regards,
      Oleg.

    • Jeremy

      Hey Mike,

      Unfortunately, I can’t help much with your question as I have a similar one. I am using a HUAWEI E160 with Oleg’s USB Host shield. I’ve had success communicating with the modem (sending/receiving SMS) via a python script when attached to my computer via USB, but getting the arduino talking to the modem via AT Commands has proved difficult so far (though I’m completely new to this technology so that doesn’t mean much).

      Let me know if you have any success looking into feasibility and I will do the same.

      Cheers,
      Jeremy

  • Patrick Delges

    Hi Oleg,

    just received your shield this morning but I have some small problems:

    I plugged an Apple keyboard.

    Your getdevdescr( 1 ) code runs fine (the first one on this page).
    But the 3rd example – getconfdescr( 1, 0 ) – doesn’t display nothing besides “Start”. So I tried the conf_descr_dump.pde example, but then the arduino reboots continuously after getconfdescr() is called.

    So I tried the keyboard polling example, which returns
    Error attempting to configure boot protocol. Return code :5

    Is there anything obvious I should check?

    Thanks,

    p

    • An Apple keyboard most likely has a hub in it so keyboard sketch won’t work with it. I’m working on the code with hub support, hoping to release it in a couple months. Post your device descriptor output here – I’ll take a look why config descriptor is not showing.

      • Patrick Delges

        Thanks for your answer. You’re right about the hub!
        Here is the device descriptor of Apple’s belgian kb without numeric keypad (well, of its hub):

        Device descriptor:
        Descriptor Length: 12
        Descriptor type: 01
        USB version: 0200
        Device class: 09
        Device Subclass: 00
        Device Protocol: 00
        Max.packet size: 40
        Vendor ID: 05AC
        Product ID: 1005
        Revision ID: 9615
        Mfg.string index: 01
        Prod.string index: 02
        Serial number index: 03
        Number of conf.: 01

        The keybard with numeric keypad has the same descriptor, but with a product ID of 1006.

        Using Apple’s System Profiler, those are the descriptors of the keyboards plugged to their hubs:

        with numeric keypad:

        Product ID: 0x0221
        Vendor ID: 0x05ac (Apple Inc.)
        Version: 0.69
        Speed: Up to 1.5 Mb/sec
        Manufacturer: Apple, Inc
        Location ID: 0xfd132000
        Current Available (mA): 100
        Current Required (mA): 20

        Without numeric keypad:

        Product ID: 0x021e
        Vendor ID: 0x05ac (Apple Inc.)
        Version: 0.70
        Speed: Up to 1.5 Mb/sec
        Manufacturer: Apple Inc.
        Location ID: 0xfd131200
        Current Available (mA): 100
        Current Required (mA): 20

        Best,

        p

  • Mohit

    Hello Oleg

    I am doing a project on max3421e with PIC that i think you’ve already worked on.I searched internet for help on this particular combination but unable to find any good
    resources can you pls help me in selection of initial hardware requirement.
    Any one good link will be very helpful.

    Thanks in Advance.

    Mohit

  • Palliser

    Hello Mr. Oleg,

    Given that Arduino Due’s sam3x has usb host behavior, I thought I could use it to write/read simple text (ASCII) to/from an USB memory stick. So far, I have solved the writing part through porting a mass storage class implementation contained in an example of Atmel Studio 6, but not for the reading. I know that Atmel ported the usb host stack v2 from you (circuits@home) for Arduino. Could you tell me where I can obtain the mentioned stack? Thank you very much,

    Palliser

  • Panther9

    Hello! I hope I’m in the right place to ask this: I’ve an Arduino MEGA ADK board and it has an onboard USB host, I need to make a program that will read the Hardware ID of the devices I connect. Whether the device is a USB Flash, or any other USB Device, the program has to read the Hardware ID of the device, and, the program will have a list of specific Hardware IDs to which it would turn on an LED, and if the Hardware ID of the connected device is not on the list, another LED would turn on, indicating the error, or so… this should be possible, but I don’t know how to write code for such a thing. Please help. Thank you in advance!

  • Dimitri

    Hi Oleg,
    my USB host shield is working flawlessy with my USB device, but the only problem I have is that when I use a similar device (same endpoints values, same interface, same config. value, and so on, the only difference is “product id”), it doensn’t work. I’m almost sure it’s beacuse of the usb address.
    Indeed I “hardcoded” address 0 to my sketch. How can I set the sketch to automatically recognize the address of the device connected?

    • You can’t use address 0.

      Device addressing is handled by the class – you can’t use it directly and it is also not necessary. If you need several devices create an instance of the class for each device.

      Nothing bad can happen “because of the USB address”. As long as addresses are unique (and different from 0) they don’t affect anything.

      • Dimitri

        so what should I use when I call methods like getDevDescr or inTransfer?
        If I use 0 it works perfectly on one of my device, while it doesn’t work on another one identical (except for the product ID)

        • you don’t use those methods directly. The device driver uses them with address stored in bAddress data member. At the same time, the driver provides methods to send/receive data. If you can’t use one of the existing drivers and want to develop your own just do it the same way other drivers do it – get the address, store it in bAddress, then set the device with this address.

  • Dimitri

    thank you, yes indeed I wrote my own drivers for my device. but it only works with address = 0 when I use those methods. I can’t find bAddress inside the USB class, how can I get the address then?

  • Will the above codes work on Arduino due?

  • So can you please help me..
    I have Arduino Due Board on that one USB Device is connected to Native port of Due and programmer port of Due is connected to pc…i want to read Vendor ID and Product Id of Connected USB Device..How can i start…?

  • Oleg I am realy stucked…..I am not able to creat library to get the USB Descriptor data as mentioned in above tutorials for Arduino Due..
    Can you please provide me the library as above code work on Arduino due…?

  • Walson

    Hi oleg, I want to read my usb device’s name, some like Logic USB Keyboard shown in control pannel, what should I do? Thanks a lot!

  • satougasinodangan

    Hi oleg,

    Please tell me if you feel up to it.
    Do you plan to support the keyboard to be connected via an internal USB hub?
    When do you support?

    I’m very troubled, in this matter.

    Thank you

  • ChunWang

    Hi oleg,
    Did you use the host sheild to communicate with a Dance pad that just like this(http://detail.tmall.com/item.htmspm=a230r.1.14.1.B3UePb&id=14484075366&ad_id=&am_id=&cm_id=140105335569ed55e27b&pm_id=&abbucket=9),can you give me some advice.
    Thank you.

    • I don’t know what this is. Post descriptors when you get it.

      • ChunWang

        i’m already get it,I hnow it’s a gampad,but i’m don’t hnow how to send message to it in your code.
        *********USBHID_desc.ino*****************
        Opening port
        Port open
        Start
        0000: 05 01 09 04 A1 01 A1 02 75 08 95 05 15 00 26 FF
        0010: 00 35 00 46 FF 00 09 30 09 30 09 30 09 30 09 31
        0020: 81 02 75 04 95 01 25 07 46 3B 01 65 14 09 00 81
        0030: 42 65 00 75 01 95 0A 25 01 45 01 05 09 19 01 29
        0040: 0A 81 02 06 00 FF 75 01 95 0A 25 01 45 01 09 01
        0050: 81 02 C0 A1 02 75 08 95 04 46 FF 00 26 FF 00 09
        0060: 02 91 02 C0 C0
        Usage Page Gen Desktop Ctrls(01)
        Usage Game Pad
        Collection Application
        Collection Logical
        Report Size(08)
        Report Count(05)
        Logical Min(00)
        Logical Max(FF00)
        Physical Min(00)
        Physical Max(FF00)
        Usage X
        Usage X
        Usage X
        Usage X
        Usage Y
        Input(00000010)
        Report Size(04)
        Report Count(01)
        Logical Max(07)
        Physical Max(3B01)
        Unit(14)
        Usage Undef
        Input(01000010)
        Unit(00)
        Report Size(01)
        Report Count(0A)
        Logical Max(01)
        Physical Max(01)
        Usage Page Button(09)
        Usage Min(01)
        Usage Max(0A)
        Input(00000010)
        Usage Page Undef(00)
        Report Size(01)
        Report Count(0A)
        Logical Max(01)
        Physical Max(01)
        Usage
        Input(00000010)
        End Collection
        Collection Logical
        Report Size(08)
        Report Count(04)
        Physical Max(FF00)
        Logical Max(FF00)
        Usage
        Output(00000010)
        End Collection
        End Collection Game Pad X X X X Y(01)(7F)(7F)(7F)(7F)
        Undef(0F)
        Btn0001
        (01) Btn0002
        (00) Btn0003
        (00) Btn0004
        (00) Btn0005
        (00) Btn0006
        (00) Btn0007
        (00) Btn0008
        (00) Btn0009
        (01) Btn000A
        (01)
        (01)(01)(01)(01)(01)(00)(00)(00)(01)(01)

        ***********USB_dec.ino******

        Opening port
        Port open
        Start

        01

        Device descriptor:
        Descriptor Length: 12
        Descriptor type: 01
        USB version: 0100
        Device class: 00
        Device Subclass: 00
        Device Protocol: 00
        Max.packet size: 08
        Vendor ID: 0079
        Product ID: 0011
        Revision ID: 0106
        Mfg.string index: 00
        Prod.string index: 02
        Serial number index: 00
        Number of conf.: 01

        Configuration descriptor:
        Total length: 0022
        Num.intf: 01
        Conf.value: 01
        Conf.string: 00
        Attr.: 80
        Max.pwr: 32

        Interface descriptor:
        Intf.number: 00
        Alt.: 00
        Endpoints: 01
        Intf. Class: 03
        Intf. Subclass: 00
        Intf. Protocol: 00
        Intf.string: 00
        Unknown descriptor:
        Length: 09
        Type: 21
        Contents: 100121012265000705

        Endpoint descriptor:
        Endpoint address: 81
        Attr.: 03
        Max.pkt size: 0008
        Polling interval: 0A

        Addr:1(0.0.1)

  • Felipe

    Good afternoon good sir, loved your work, but i am new to the arduino usb host concept. Would this library suffice the communication between a usb sound card with the arduino due? I work with speech recognition in my university, been doing my research with MATLAB since day 1, and now for my final project i want to apply my algorithm on a embedded system. Could share a light over this subject? Thanks in advance and sorry for my bad english 🙂

  • Hello I have a trouble regarding USB Bus transfer (Bulk transfer).My device send 2048 bytes after request in less than of a millesecond.I need to send this data thru serial port using max speed 115200 bps.How i can resolve the critical time ? (no lossing data received). MAX3241 have inside two buffer of 64 bytes , of course the data tranfer is 32 consecutive data sending reffered to buffer size.
    Can you help me ?
    I have a USB shield 2.0 this shield support standard USB 2.0
    (my bulk trasnfer work with speed USB 2.0 max 480 Mbit/s)

    Thank’s in advance

    Pietro

    • If you are getting more data from USB than you can send out via serial your buffers will always be overflowing, adding extra memory will only add time before it happens.

  • Raichine

    Hello
    i just bought a arduino leonardo and a usb host shield from arduino.cc . I was wondering if i can use the last version of the library in order to get the ID Product.