I am trying to interface with a device connected to my Ubuntu 16 system(Python ver 2.7.12). When I try to write to the device, I am getting a write timeout (similar with reading from the device).
According to what little documentation I have, the HID interface is implemented in interface 3, in addition to the standard endpoint (EP)0 the device supports EP4 IN (device to host) interrupt transfer type, and EP5 OUT( host to device) interrupt transfer type. It also states the USB Bulk is based on request-response message pair with a message format of 64 bytes with the first byte being the 'op code'. For a 'get version' command the op-code is 0x02, and the rest is ignored.
I am new to both Python and USB, so probably have this wrong but I am trying to write to the 'OUT' interface and then read from the 'IN' interface. I have noticed that when I plug the device into the Ubuntu system I get a new device /dev/usb/hiddev0 but couldn't seem to write to that so tried to connect to interface 3 and grab the In/Out interfaces. Also I added in what I thought was the call for PYUSB_DEBUG but I do not see any more output than without it.
With the following code I do see the device, and I get an IN/OUT interface but write/reads always timeout. I do not know what I am missing. Thank you very much for any help
import usb.core
import usb.util
from usb.core import *
import sys
import os
import binascii
import time
import serial
import itertools
idV = 0x2abf
idP = 0x0505
# doesnt seem to write anything to log?!
os.environ['PYUSB_DEBUG'] = 'debug'
#os.environ['PYUSB_LOG_FILENAME'] = "pyusb.log" #never written
print "finding idVendor = {}, idProduct= {}".format(idV, idP)
device = usb.core.find(idVendor=idV, idProduct=idP)
if device is None:
print ("Device not found")
exit()
# free up the device from the kernal
for cfg in device:
for intf in cfg:
if device.is_kernel_driver_active(intf.bInterfaceNumber):
try:
device.detach_kernel_driver(intf.bInterfaceNumber)
except usb.core.USBError as e:
sys.exit("Could not detach kernel driver from interface({0}): {1}".format(intf.bInterfaceNumber, str(e)))
# try default conf
print "setting configuration"
device.set_configuration()
print "config set"
print "trying to claim device"
try:
usb.util.claim_interface(device, 0)
print "claimed device"
except usb.core.USBError as e:
print "Error occurred claiming " + str(e)
sys.exit("Error occurred on claiming")
print "device claimed"
# get enpoint instance
cfg = device.get_active_configuration()
print "***********"
for intf in cfg:
print "intf= " + str(intf)
print "***********"
# from document:
# The HID interface is implemented on Interface 3, in addition to standard endpoint (er)0, the device supports
# EP4 IN (device to host) interrupt transfer type, and EP5 OUT (host to device) interrupt transfer type
# Note: EP$ seems to come back as 0x84 while EP5 comes back as 0x05
intf = cfg[(3, 0)]
# get the BULK OUT descriptor
epo = usb.util.find_descriptor(
intf,
# match our first out endpoint
custom_match= \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
assert epo is not None
# get the BULK IN descriptor
epi = usb.util.find_descriptor(
intf,
# match our first out endpoint
custom_match= \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
assert epi is not None
print "write the data"
# commands are 64 bytes long, first byte is command code, 02 is 'get version', it doesn't need any of the other bytes set
try:
# don't think I can use [0x00]*63 because it will be all pointers to same object?, call them out to be safe
test = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
mybuff = b'\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
#device.write(epo,mybuff,1) #timeout on write
#epo.write(mybuff) #timeout on write
epo.write(mybuff.encode('utf-8')) #timeout on write
except usb.core.USBError as e:
print "Write USBError: " + str(e)
sys.exit()
print "done writing"
print "try read?"
try:
#info = device.read(0x84, 8)
info = epo.read(epi.bEndpointAddress,epi.wMaxPacketSize)
except usb.core.USBError as e:
print "Read USBError: " + str(e)
sys.exit()
print "read: " + str(info)
Output:
finding idVendor = 10943, idProduct= 1285
setting configuration
config set
trying to claim device
claimed device
device claimed
***********
< skipping audio interfaces>
intf= INTERFACE 3: Human Interface Device ====================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x3
bAlternateSetting : 0x0
bNumEndpoints : 0x2
bInterfaceClass : 0x3 Human Interface Device
bInterfaceSubClass : 0x0
bInterfaceProtocol : 0x0
iInterface : 0x8 PlaylistControl
ENDPOINT 0x84: Interrupt IN ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x84 IN
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0xa
ENDPOINT 0x5: Interrupt OUT ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x5 OUT
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0xa
***********
write the data
Write USBError: [Errno 110] Operation timed out
I suppose you are reusing the device while testing your code and your problems occur when you are executing it multiple times. You should use
usb.util.dispose_resources(device)
at the end of your code. Try using
device.reset()
after
device = usb.core.find(...)
and before doing anything else with the device if you suspect the earlier code run closed unclean.