如何使用 PyUSB 写入控制端点
How to write to Control Endpoint with PyUSB
我有一个 USB 设备,下面的代码
import usb.core
import usb.util
device = usb.core.find(idVendor=0xC251, idProduct=0x2201)
print(device)
产生
DEVICE ID c251:2201 on Bus 002 Address 020 =================
bLength : 0x12 (18 bytes)
bDescriptorType : 0x1 Device
bcdUSB : 0x200 USB 2.0
bDeviceClass : 0x0 Specified at interface
bDeviceSubClass : 0x0
bDeviceProtocol : 0x0
bMaxPacketSize0 : 0x40 (64 bytes)
idVendor : 0xc251
idProduct : 0x2201
bcdDevice : 0x100 Device 1.0
iManufacturer : 0x1 LASER Driver
iProduct : 0x2 LASER Driver IJS
iSerialNumber : 0x3 0001A0000000
bNumConfigurations : 0x1
CONFIGURATION 1: 100 mA ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x2 Configuration
wTotalLength : 0x22 (34 bytes)
bNumInterfaces : 0x1
bConfigurationValue : 0x1
iConfiguration : 0x0
bmAttributes : 0xc0 Self Powered
bMaxPower : 0x32 (100 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 : 0x0
bInterfaceProtocol : 0x0
iInterface : 0x4 HID
ENDPOINT 0x81: Interrupt IN ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x81 IN
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x1
in Ubuntu 20.04 under Python 3. 可以看出没有OUT
端点。我不是 USB 方面的专家,但据我所知,我们需要一个输出端点来向设备发送数据,所以这个设备看起来像一个只读设备。
但是,我知道有一些方法可以将 sending/writing 数据传输到设备,因为它是一个激光控制器,并且从 Windows 我可以转动 on/off 激光,改变强度等。我有此控制器的部分 C++ 源代码,用于 Windows,它使用 hidapi. According to the documentation of hid_write
it writes to the "Control Endpoint" when there is no other out endpoint, which seems to be the case here. So now I want to replicate this from Python using PyUSB。
到目前为止我有这个
import usb.core
import usb.util
import array
device = usb.core.find(idVendor=0xC251, idProduct=0x2201)
if device is None:
raise RuntimeError('Device not found')
interface = device[0].interfaces()[0]
endpoint = device[0].interfaces()[0].endpoints()[0] # This is the in endpoint, I can read the status of the laser from here and it works fine.
if device.is_kernel_driver_active(interface.bInterfaceNumber):
device.detach_kernel_driver(interface.bInterfaceNumber)
cmd = chr(90) # This is the command to turn off the laser.
packet = chr(0) + cmd + chr(0)*(64-len(cmd)-1) # The first byte has to be always 0, see https://codedocs.xyz/GerryFerdinandus/hidapi/group__API.html#gad14ea48e440cf5066df87cc6488493af
packet = array.array('B', [ord(c) for c in packet])
bytes_sent = endpoint.write(packet)
print(bytes_sent) # This prints out 64 so it is fine.
这似乎在写作,但激光什么也没做(它应该关闭)。我怀疑它以某种方式写入“IN 端点”而不是“控制端点”。我想 将此 packet
发送到控制端点 。如何做到这一点?
PD:我也试过了
device.write(0x0, packet)
但这会产生 ValueError: Invalid endpoint address 0x0
.
要写入端点 0,您需要 device.ctrl_transfer(bmRequestType, bmRequest, wValue, wIndex, packet)
而不是 endpoint.write(packet)
。
bmRequestType
、bmRequest
、wValue
和wIndex
对应USB控制请求中相同的元素。 Windows 软件使用 hidapi
的事实表明控制传输是根据 USB HID 规范完成的。
This answer here on Stack Overflow 描述了如何在普通 PyUSB 上进行 USB HID set/get 操作。
但是由于你移植的源代码使用了hidapi
,使用Python hidapi interface might make the process more straightforward. 有一个使用hidapi
的例子在Python,答案也讲了关于备选方案。
我有一个 USB 设备,下面的代码
import usb.core
import usb.util
device = usb.core.find(idVendor=0xC251, idProduct=0x2201)
print(device)
产生
DEVICE ID c251:2201 on Bus 002 Address 020 =================
bLength : 0x12 (18 bytes)
bDescriptorType : 0x1 Device
bcdUSB : 0x200 USB 2.0
bDeviceClass : 0x0 Specified at interface
bDeviceSubClass : 0x0
bDeviceProtocol : 0x0
bMaxPacketSize0 : 0x40 (64 bytes)
idVendor : 0xc251
idProduct : 0x2201
bcdDevice : 0x100 Device 1.0
iManufacturer : 0x1 LASER Driver
iProduct : 0x2 LASER Driver IJS
iSerialNumber : 0x3 0001A0000000
bNumConfigurations : 0x1
CONFIGURATION 1: 100 mA ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x2 Configuration
wTotalLength : 0x22 (34 bytes)
bNumInterfaces : 0x1
bConfigurationValue : 0x1
iConfiguration : 0x0
bmAttributes : 0xc0 Self Powered
bMaxPower : 0x32 (100 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 : 0x0
bInterfaceProtocol : 0x0
iInterface : 0x4 HID
ENDPOINT 0x81: Interrupt IN ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x81 IN
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x1
in Ubuntu 20.04 under Python 3. 可以看出没有OUT
端点。我不是 USB 方面的专家,但据我所知,我们需要一个输出端点来向设备发送数据,所以这个设备看起来像一个只读设备。
但是,我知道有一些方法可以将 sending/writing 数据传输到设备,因为它是一个激光控制器,并且从 Windows 我可以转动 on/off 激光,改变强度等。我有此控制器的部分 C++ 源代码,用于 Windows,它使用 hidapi. According to the documentation of hid_write
it writes to the "Control Endpoint" when there is no other out endpoint, which seems to be the case here. So now I want to replicate this from Python using PyUSB。
到目前为止我有这个
import usb.core
import usb.util
import array
device = usb.core.find(idVendor=0xC251, idProduct=0x2201)
if device is None:
raise RuntimeError('Device not found')
interface = device[0].interfaces()[0]
endpoint = device[0].interfaces()[0].endpoints()[0] # This is the in endpoint, I can read the status of the laser from here and it works fine.
if device.is_kernel_driver_active(interface.bInterfaceNumber):
device.detach_kernel_driver(interface.bInterfaceNumber)
cmd = chr(90) # This is the command to turn off the laser.
packet = chr(0) + cmd + chr(0)*(64-len(cmd)-1) # The first byte has to be always 0, see https://codedocs.xyz/GerryFerdinandus/hidapi/group__API.html#gad14ea48e440cf5066df87cc6488493af
packet = array.array('B', [ord(c) for c in packet])
bytes_sent = endpoint.write(packet)
print(bytes_sent) # This prints out 64 so it is fine.
这似乎在写作,但激光什么也没做(它应该关闭)。我怀疑它以某种方式写入“IN 端点”而不是“控制端点”。我想 将此 packet
发送到控制端点 。如何做到这一点?
PD:我也试过了
device.write(0x0, packet)
但这会产生 ValueError: Invalid endpoint address 0x0
.
要写入端点 0,您需要 device.ctrl_transfer(bmRequestType, bmRequest, wValue, wIndex, packet)
而不是 endpoint.write(packet)
。
bmRequestType
、bmRequest
、wValue
和wIndex
对应USB控制请求中相同的元素。 Windows 软件使用 hidapi
的事实表明控制传输是根据 USB HID 规范完成的。
This answer here on Stack Overflow 描述了如何在普通 PyUSB 上进行 USB HID set/get 操作。
但是由于你移植的源代码使用了hidapi
,使用Python hidapi interface might make the process more straightforward. hidapi
的例子在Python,答案也讲了关于备选方案。