# stm32 USB composite device

There is a need to implement on stm32 usb composite device. The problem is that all USB devices are the same, will not work in parallel (three smart card readers connected to one UART). That is, you just need to track which device the command is sent to and do some machinations outside the USB logic (turn on the selected card, turn off the rest).

It seems to me that the full implementation of USB Composite device complicates the code too much, and I can not defeat it in any way.

Is there an easier option to implement this task without unnecessary code complications?

Once again, you need to display 3 USB devices in the device Manager, each of which will accept commands, but from the microcontroller they will act on the same algorithm.

UPDATE

The problem is this. At the present time one unit uses 3 end points. In total, I should have three - it's 9 endpoints + zero.

And stm only supports 7. I need to somehow at the software level to display three connected devices, but from the stm side to process the data coming to them through one processor.

For my purposes, I need only some device ID, which was accessed from the host (address, index, anything). Is it possible to do this without increasing the number of endpoints and not prescribing each individual device initialization and handler?

Hope, so a bit clearer)

Give the device descriptor

  0x09,   /* bLength: Configuration Descriptor size */
USB_DESC_TYPE_CONFIGURATION,   /* bDescriptorType: Configuration */
SMARTCARD_SIZ_CONFIG_DESC,

0x00,
0x01,   /* bNumInterfaces: 1 interface */
0x01,   /* bConfigurationValue: */
0x04,   /* iConfiguration: */
0x80,         /*bmAttributes: bus powered */
0x32,   /* MaxPower 100 mA */

/********************  CCID **** interface ********************/
0x09,   /* bLength: Interface Descriptor size */
0x04,   /* bDescriptorType: */
0x00,   /* bInterfaceNumber: Number of Interface */
0x00,   /* bAlternateSetting: Alternate setting */
0x03,   /* bNumEndpoints: 3 endpoints used */
0x0B,   /* bInterfaceClass: user's interface for CCID */
0x00,   /* bInterfaceSubClass : */
0x00,   /* nInterfaceProtocol : None */
0x05,   /* iInterface: */

/*******************  CCID class descriptor ********************/
0x36,   /* bLength: CCID Descriptor size */
0x21,    /* bDescriptorType: Functional Descriptor type. */
0x10,    /* bcdCCID(LSB): CCID Class Spec release number (1.00) */
0x01,   /* bcdCCID(MSB) */

0x02,    /* bMaxSlotIndex :highest available slot on this device */
0x03,    /* bVoltageSupport: bit Wise OR for 01h-5.0V 02h-3.0V
04h 1.8V*/

0x01,0x00,0x00,0x00,   /* dwProtocols: 0001h = Protocol T=0 */
0x10,0x0E,0x00,0x00,   /* dwDefaultClock: 3.6Mhz = 3600kHz = 0x0E10,
for 4 Mhz the value is (0x00000FA0) :
This is used in ETU and waiting time calculations*/
0x10,0x0E,0x00,0x00,   /* dwMaximumClock: Maximum supported ICC clock frequency
in KHz. So, 3.6Mhz = 3600kHz = 0x0E10,
4 Mhz (0x00000FA0) : */
0x00,          /* bNumClockSupported : no setting from PC
If the value is 00h, the
supported clock frequencies are assumed to be the
default clock frequency defined by dwDefaultClock
and the maximum clock frequency defined by
dwMaximumClock */

0xCD,0x25,0x00,0x00,   /* dwDataRate: Default ICC I/O data rate in bps
9677 bps = 0x25CD
for example 10752 bps (0x00002A00) */

0xCD,0x25,0x00,0x00,   /* dwMaxDataRate: Maximum supported ICC I/O data
rate in bps */
0x00,                 /* bNumDataRatesSupported :
The number of data rates that are supported by the CCID
If the value is 00h, all data rates between the default
data rate dwDataRate and the maximum data rate
dwMaxDataRate are supported.
Dont support GET_CLOCK_FREQUENCIES
*/

0x00,0x00,0x00,0x00,   /* dwMaxIFSD: 0 (T=0 only)   */
0x00,0x00,0x00,0x00,   /* dwSynchProtocols  */
0x00,0x00,0x00,0x00,   /* dwMechanical: no special characteristics */

0x38,0x00,EXCHANGE_LEVEL_FEATURE,0x00,
/* dwFeatures: clk, baud rate, voltage : automatic */
/* 00000008h Automatic ICC voltage selection
00000010h Automatic ICC clock frequency change
00000020h Automatic baud rate change according to
active parameters provided by the Host or self
determined 00000100h CCID can set
ICC in clock stop mode

Only one of the following values may be present to
select a level of exchange:
00010000h TPDU level exchanges with CCID
00020000h Short APDU level exchange with CCID
00040000h Short and Extended APDU level exchange
If none of those values : character level of exchange*/
0x0F,0x01,0x00,0x00,  /* dwMaxCCIDMessageLength: Maximum block size + header*/
/* 261 + 10   */

0x00,          /* bClassGetResponse*/
0x00,          /* bClassEnvelope */
0x00,0x00,     /* wLcdLayout : 0000h no LCD. */
0x00,          /* bPINSupport : no PIN verif and modif  */
0x03,          /* bMaxCCIDBusySlots    */

/********************  CCID   Endpoints ********************/
0x07,   /*Endpoint descriptor length = 7*/
0x05,   /*Endpoint descriptor type */
0x02,   /*Bulk endpoint type */
LOBYTE(CCID_BULK_EPIN_SIZE),
HIBYTE(CCID_BULK_EPIN_SIZE),
0x00,   /*Polling interval in milliseconds */

0x07,   /*Endpoint descriptor length = 7 */
0x05,   /*Endpoint descriptor type */
0x02,   /*Bulk endpoint type */
LOBYTE(CCID_BULK_EPOUT_SIZE),
HIBYTE(CCID_BULK_EPOUT_SIZE),
0x00,   /*Polling interval in milliseconds*/

0x07,   /*bLength: Endpoint Descriptor size*/
0x05,   /*bDescriptorType:*/
0x03,   /* bmAttributes: Interrupt endpoint */
LOBYTE(CCID_INTR_EPIN_SIZE),
HIBYTE(CCID_INTR_EPIN_SIZE),
0x18    /*Polling interval in milliseconds */


In response to RDR_to_PC_NotifySlotChange, I send the answer 3F, which, in theory, should mean that I have three slots with cards, each of which is inserted into the slot and works. However, windows displays and sees only one slot. In General,that is why it was decided to try to make a composite device.

UPDATE

Well, the previous idea was bad. What could be the error of the multi-slot approach? As I understand it, the maximum slot index is set in the descriptor, and the state of each of the available slots is passed to RDR_to_PC_NotifySlotChange. But why change these values in the required Windows stubbornly continues to appeal only to the zero slot number and ignores the rest (checked on the UWP app, in debug it is visible that Windows only gets one card). Maybe I'm missing something?

• It's not really clear what you're trying to do? Do you want to have 3x usb-cdc, or 1x usb-cdc + software multiplexing? Any approach will require code to be written. – domen Jun 3 '19 at 8:31
• I want the least energy-intensive reproduction of one device for several. The only task that would distinguish its duplicated copies from a single instance is a certain marker, which would make it clear how the device was accessed (marker or index). Writing code does not bother me, I am confused by the extra complexity. The problem is that it is a CID device, information on which is not particularly. Thanks for the tip, first time I hear about multiplexing device, I'll go read about it. – Egor Vasilyev Jun 3 '19 at 8:43
• The USB CCID specs (which is probably what you should implement, since your goal is to provide smart card reader interfaces) allows for multi-slot. Why not implement a single CCID device with three smart card slots, instead of a composite device acting as a triple CCID device? It isn't clear. – dim Jun 3 '19 at 14:05
• windows somehow does not display the rest of the slots, as well as the programs that I found – Egor Vasilyev Jun 4 '19 at 3:56
• It will be quite difficult for you to exceed the number of endpoints available on your chosen STM32. In order to "trick" the host into thinking you have more endpoints than you really do you would have to do trickery on the protocol level (or somehow predict which endpoint would be accessed next and change the address on the fly, which is very hard if not impossible). You might want to reconsider your design: Either figuring out what's wrong with the multi-slot approach or choosing a new microcontroller. – Los Frijoles Jun 4 '19 at 6:37