USB Libraries Help > USB Device Libraries > USB Device Layer Library > Using the Library > How the Library Works > String Descriptor Table
MPLAB Harmony USB Stack
String Descriptor Table

The Device Layer allows the application to specify string descriptors via a String Descriptor Table. When the USB Host requests for a string by its index and language ID, the Device Layer looks for the corresponding string descriptor in the String Descriptor Table. There are two possible methods of specifying this String Descriptor Table, Basic and Advanced. These methods are discussed here.

Basic String Descriptor Table

The Basic String Descriptor Table should be used when the USB Device Application has equal number of string descriptors for each language string and the String Descriptor Indexes are continuous. This is the default method of specifying the String Descriptor Table. Each entry in the table contains the following information

  • The size of the entry
  • The descriptor type, which is always set to USB_DESCRIPTOR_STRING
  • The array containing the string

The first entry in the String Descriptor Table, at index 0 of the table, will always contain the Lang ID string. This string specifies the one language ID of the String Descriptor that this application intends to support. The subsequent entries in the String Descriptor Table contain the actual string descriptor. Each language must have an equal set of the string descriptors. The Device layer will associate each set of string descriptors with language ID specified in the language ID string descriptor. The following code shows an example of a Basic String Descriptor table. 

Example:  

/* This code shows an example of a Basic String Descriptor Table. In
 * this example, the table contains five entries. The first entry is the
 * language ID string. The second entry in the manufacturer string and the third
 * entry is the product string for language ID 0x0409. The fourth and the fifth
 * entry is the manufacture and product string, respectively for the language ID
 * 0x040C. */

/**************************************************************************
*  Language ID string descriptor. Note that this contains two Language IDs.
**************************************************************************/
const struct
{
    uint8_t bLength;
    uint8_t bDscType;
    uint16_t string[1];
}
sd000 =
{
    sizeof(sd000),          // Size of this descriptor in bytes
    USB_DESCRIPTOR_STRING,  // STRING descriptor type
    {0x0409, 0x040C}        // Language ID
};

/*******************************************
 *  Manufacturer string descriptor
 *******************************************/
const struct
{
    uint8_t bLength;        // Size of this descriptor in bytes
    uint8_t bDscType;       // STRING descriptor type
    uint16_t string[25];    // String
}
sd001 =
{
    sizeof(sd001),
    USB_DESCRIPTOR_STRING,
    {'M','i','c','r','o','c','h','i','p',' ',
     'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'}
};

/*******************************************
 *  Product string descriptor
 *******************************************/
const struct
{
    uint8_t bLength;        // Size of this descriptor in bytes
    uint8_t bDscType;       // STRING descriptor type
    uint16_t string[22];    // String
}
sd002 =
{
    sizeof(sd002),
    USB_DESCRIPTOR_STRING,
    {'S','i','m','p','l','e',' ','C','D','C',' ','D','e','v','i','c','e',' ','D','e','m','o' }
};

/*******************************************
 *  Manufacturer string descriptor
 *******************************************/
const struct
{
    uint8_t bLength;        // Size of this descriptor in bytes
    uint8_t bDscType;       // STRING descriptor type
    uint16_t string[25];    // String
}
sd003 =
{
    sizeof(sd003),
    USB_DESCRIPTOR_STRING,
    {'M','i','c','r','o','c','h','i','p',' ',
     'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'}
};

/*******************************************
 *  Product string descriptor
 *******************************************/
const struct
{
    uint8_t bLength;        // Size of this descriptor in bytes
    uint8_t bDscType;       // STRING descriptor type
    uint16_t string[22];    // String
}
sd004 =
{
    sizeof(sd004),
    USB_DESCRIPTOR_STRING,
    {'S','i','m','p','l','e',' ','C','D','C',' ','D','e','v','i','c','e',' ','D','e','m','o' }
};

/***************************************
 * Array of string descriptors
 ***************************************/
USB_DEVICE_STRING_DESCRIPTORS_TABLE stringDescriptors[3]=
{
    /* This is the language ID string */
    (const uint8_t *const)&sd000,

    /* This string descriptor at index 1 will be returned when the host request
     * for a string descriptor with index 1 and language ID 0x0409. */
    (const uint8_t *const)&sd001,

    /* This string descriptor at index 2 will be returned when the host request
     * for a string descriptor with index 2 and language ID 0x0409. */
    (const uint8_t *const)&sd002,

    /* This string descriptor at index 3 will be returned when the host request
     * for a string descriptor with index 1 and language ID 0x040C. */
    (const uint8_t *const)&sd003,

    /* This string descriptor at index 4 will be returned when the host request
     * for a string descriptor with index 2 and language ID 0x040C. */
    (const uint8_t *const)&sd004
};
Advanced String Descriptor Table

The Advanced String Descriptor Table should be used when the application needs to specify string descriptors with string indexes that are not continuous. One such example is the Microsoft OS String Descriptor. The index of this string descriptor is 0xEE. If the application were to use the Basic String Descriptor Table , this would require the String Descriptor Table to have at least 0xED entries (valid or invalid) before the entry for the Microsoft OS String Descriptor. This arrangement may not be optimal. Using the Ad Advanced String Descriptor Table mitigates this problem. The Advanced String Descriptor Table format is enabled only when USB_DEVICE_STRING_DESCRIPTOR_TABLE_ADVANCED_ENABLE configuration option is specified in the system_config.h. Each entry in the Advanced String Descriptor Table contains the following information:

  • The index of the string descriptor
  • The language ID of the string descriptor
  • The size of the entry, which is two more than the length of the string
  • The descriptor type, which is always set to USB_DESCRIPTOR_STRING
  • The array containing the string

The first such entry in the Advanced String Descriptor Table specifies the language ID string. The string index and the language ID of this entry should be zero. This first entry is then followed by the actual string descriptors. Unlike the Basic String Descriptor Table, the position of the string descriptor in the Advanced String Descriptor Table does not define the String Descriptor Index that the host must to use to identify the string.Instead, the index of the string is specified by the stringIndex member of the Advanced String Descriptor Table table entry. The following code shows an example of the Advanced String Descriptor table. 

Example:  

/* This code shows an example of an Advanced String Descriptor Table.
 * The Advanced String Descriptor table should be used when multiple languages
 * are needed to be supported. In this example, two languages are supported*/

/**********************************************************
 * Language ID string descriptor. Note that stringIndex and
 * language ID are always 0 for this descriptor.
 ***********************************************************/
const struct __attribute__ ((packed))
{
    uint8_t stringIndex;    // Index of the string descriptor
    uint16_t languageID ;   // Language ID of this string.
    uint8_t bLength;        // Size of this descriptor in bytes
    uint8_t bDscType;       // STRING descriptor type
    uint16_t string[2];     // String
}
sd000 =
{
    0,                      // Index of this string is 0
    0,                      // This field is always blank for String Index 0
    sizeof(sd000)- 3,       // Should always be set to this.
    USB_DESCRIPTOR_STRING,
    {0x0409, 0x040C}        // Language ID
};

/******************************************************
 *  Manufacturer string descriptor for language 0x0409
 ******************************************************/
const struct __attribute__ ((packed))
{
    uint8_t stringIndex;    // Index of the string descriptor
    uint16_t languageID ;   // Language ID of this string.
    uint8_t bLength;        // Size of this descriptor in bytes
    uint8_t bDscType;       // STRING descriptor type
    uint16_t string[25];    // String
}
sd001 =
{
    1,      // Index of this string descriptor is 1.
    0x0409, // Language ID of this string descriptor is 0x0409 (English)
    sizeof(sd001) - 3,
    USB_DESCRIPTOR_STRING,
    {'M','i','c','r','o','c','h','i','p',' ',
    'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'}
};

/******************************************************
 *  Manufacturer string descriptor for language 0x040C
 ******************************************************/
const struct __attribute__ ((packed))
{
    uint8_t stringIndex;    // Index of the string descriptor
    uint16_t languageID ;   // Language ID of this string.
    uint8_t bLength;        // Size of this descriptor in bytes
    uint8_t bDscType;       // STRING descriptor type
    uint16_t string[25];    // String
}
sd002 =
{
    1,      // Index of this string descriptor is 1.
    0x040C, // Language ID of this string descriptor is 0x040C (French)
    sizeof(sd001) - 3,
    USB_DESCRIPTOR_STRING,
    {'M','i','c','r','o','c','h','i','p',' ',
    'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'}
};

/************************************************
 *  Product string descriptor for language 0x409
 ************************************************/
const struct __attribute__ ((packed))
{
    uint8_t stringIndex;    // Index of the string descriptor
    uint16_t languageID ;   // Language ID of this string.
    uint8_t bLength;        // Size of this descriptor in bytes
    uint8_t bDscType;       // STRING descriptor type
    uint16_t string[22];    // String
}
sd003 =
{
    2,       // Index of this string descriptor is 2.
    0x0409,  // Language ID of this string descriptor is 0x0409 (English)
    sizeof(sd002) - 3,
    USB_DESCRIPTOR_STRING,
    {'S','i','m','p','l','e',' ','C','D','C',' ','D','e','v','i','c','e',' ','D','e','m','o' }
};

/************************************************
 *  Product string descriptor for language 0x40C
 ************************************************/
const struct __attribute__ ((packed))
{
    uint8_t stringIndex;    // Index of the string descriptor
    uint16_t languageID ;   // Language ID of this string.
    uint8_t bLength;        // Size of this descriptor in bytes
    uint8_t bDscType;       // STRING descriptor type
    uint16_t string[22];    // String
}
sd004 =
{
    2,       // Index of this string descriptor is 2.
    0x0409,  // Language ID of this string descriptor is 0x040C (French)
    sizeof(sd002) - 3,
    USB_DESCRIPTOR_STRING,
    {'S','i','m','p','l','e',' ','C','D','C',' ','D','e','v','i','c','e',' ','D','e','m','o' }
};

/***************************************************************
 * Array of string descriptors. The entry order does not matter.
 ***************************************************************/
USB_DEVICE_STRING_DESCRIPTORS_TABLE stringDescriptors[5]=
{
    (const uint8_t *const)&sd000,
    (const uint8_t *const)&sd001,   // Manufacturer string for language 0x0409
    (const uint8_t *const)&sd002,   // Manufacturer string for language 0x040C
    (const uint8_t *const)&sd003,   // Product string for language 0x0409
    (const uint8_t *const)&sd004,   // Product string for language 0x040C
};