Search code examples
pythonpyusb

What does dev[0][(0,0)][0] mean?


I am implementing this program to read usb data from a usb mouse and display it. The program produces the correct output. It also works for other usb devices. The code is as follows

import sys
import usb.core
import usb.util

dev=usb.core.find(idVendor=0x1c4f, idProduct=0x0032)
interface=0
endpoint = dev[0][(0,0)][0]
if dev.is_kernel_driver_active(interface) is True:
    dev.detach_kernel_driver(interface)
    usb.util.claim_interface(dev,interface)

collected = 0
attempts = 50
while collected < attempts:
    try:
        data = dev.read(endpoint.bEndpointAddress,endpoint.wMaxPacketSize)
        collected += 1
        print data
    except usb.core.USBError as e :
        data = None
        if e.args == ('Operation timed out',):
            continue
usb.util.release_interface(dev,interface)
dev.attach_kernel_driver(interface)

I have trouble understanding the following lines

interface=0

why does it need to be equal to zero? Changing it produces an error.

What does the following line do?

endpoint = dev[0][(0,0)][0]

I have learnt what endpoint means from [this] (http://www.usbmadesimple.co.uk/ums_3.htm) website, but still it don't understand what [0][(0,0)[0]. Changing this also gives an error. The pyusb docs/tutorials too aren't much help

EDIT

As Suggested by Martin Evans in the comments below I added print dev after dev = [0][(0,0)][0] and I got the following output.

DEVICE ID 1c4f:0002 on Bus 002 Address 003 =================
 bLength                :   0x12 (18 bytes)
 bDescriptorType        :    0x1 Device
 bcdUSB                 :  0x110 USB 1.1
 bDeviceClass           :    0x0 Specified at interface
 bDeviceSubClass        :    0x0
 bDeviceProtocol        :    0x0
 bMaxPacketSize0        :    0x8 (8 bytes)
 idVendor               : 0x1c4f
 idProduct              : 0x0002
 bcdDevice              :  0x110 Device 1.1
 iManufacturer          :    0x1 SIGMACHIP
 iProduct               :    0x2 USB Keyboard
 iSerialNumber          :    0x0 
 bNumConfigurations     :    0x1
  CONFIGURATION 1: 98 mA ===================================
   bLength              :    0x9 (9 bytes)
   bDescriptorType      :    0x2 Configuration
   wTotalLength         :   0x3b (59 bytes)
   bNumInterfaces       :    0x2
   bConfigurationValue  :    0x1
   iConfiguration       :    0x0 
   bmAttributes         :   0xa0 Bus Powered, Remote Wakeup
   bMaxPower            :   0x31 (98 mA)
    INTERFACE 0: Human Interface Device ====================
     bLength            :    0x9 (9 bytes)
     bDescriptorType    :    0x4 Interface
     bInterfaceNumber   :    0x0
     bAlternateSetting  :    0x0
     bNumEndpoints      :    0x1
     bInterfaceClass    :    0x3 Human Interface Device
     bInterfaceSubClass :    0x1
     bInterfaceProtocol :    0x1
     iInterface         :    0x0 
      ENDPOINT 0x81: Interrupt IN ==========================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :   0x81 IN
       bmAttributes     :    0x3 Interrupt
       wMaxPacketSize   :    0x8 (8 bytes)
       bInterval        :    0xa

I got some more lines but i haven't posted it since they were of Interface 1 and I am guessing since I have interface = 0 in my code only the above lines matter.

So I think the first [0] is corresponds to bEndpointAddress , the ([0,0]) corresponds to (bmAttributes, wMaxPacketSize) and the last [0] corresponds to bInterval ? Or am I wrong?


Solution

  • Per the PyUSB tutorial:

    You can also use the subscript operator to access the descriptors randomly, like this:

    >>> # access the second configuration
    >>> cfg = dev[1]
    >>> # access the first interface
    >>> intf = cfg[(0,0)]
    >>> # third endpoint
    >>> ep = intf[2]
    

    As you can see, the index is zero-based. But wait! There is something weird in the way I access an interface... Yes, you are right, the subscript operator in the Configuration accepts a sequence of two items, with the first one being the index of the Interface and the second one, the alternate setting. So, to access the first interface, but its second alternate setting, we write cfg[(0,1)].

    So, the first subscript [0] accesses the first configuration, the second subscript [0,0] selects the first interface (with the first alternate setting) and the third subscript [0] selects the first endpoint.