1、winUSB设备开发的环境
本文选择的winUSB的开发语言为python,USB的软件包为pyUSB,首先你需要准备好python的整个开发环境与相关软件,之后在命令行中执行pip install pyusb,即可完成pyusb软件包的安装。pyusb用于实现USB主机端的USB通信功能 。
2、pyUSB的使用
pyusb的使用很简单,按如下几行代码就是发现USB设备的,可以按PID, VID的方式来查找连接到电脑上的USB设备,此时把winUSB设备连接到电脑上后,运行此代码,正常的情况下,会打印出设备的信息。
import usb.core
import usb.util
dev = usb.core.find(idVendor= 0x1234)
if dev is None:
raise ValueError('Device not found')
print(dev)
事情不会那么的顺利,我的就遇到了问题,无法正常输出设备信息,单独查看winusb设备在电脑上是枚举成功的。
程序在 运行时报错:usb.core.NoBackendError: No backend available,这是说明pyusb没有找到底层驱动的后端,需要手工增加使用的后端程序libusb-1.0.dll文件,如下方法操作即可。
点击下面的链接下载libusb-1.0.20的压缩包,解压后将MS64dlllibusb-1.0.dll复制到C:WindowsSystem32。如果还不行的话再将同一目录下的libusb-1.0.lib到Python路径下的libsite-packagesusb文件夹中。
经过以上的操作,就可以正常打印USB设备的信息了。
DEVICE ID 1234:0001 on Bus 002 Address 013 =================
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 : 0x1234
idProduct : 0x0001
bcdDevice : 0x200 Device 2.0
iManufacturer : 0x1 RT-Thread Team.
iProduct : 0x2 Lora USB
iSerialNumber : 0x3 32021919830108
bNumConfigurations : 0x1
CONFIGURATION 1: 100 mA ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x2 Configuration
wTotalLength : 0x20 (32 bytes)
bNumInterfaces : 0x1
bConfigurationValue : 0x1
iConfiguration : 0x0
bmAttributes : 0xc0 Self Powered
bMaxPower : 0x32 (100 mA)
INTERFACE 0: Vendor Specific ===========================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x0
bAlternateSetting : 0x0
bNumEndpoints : 0x2
bInterfaceClass : 0xff Vendor Specific
bInterfaceSubClass : 0x0
bInterfaceProtocol : 0x0
iInterface : 0x0
ENDPOINT 0x1: Bulk OUT ===============================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x1 OUT
bmAttributes : 0x2 Bulk
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x0
ENDPOINT 0x81: Bulk IN ===============================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x81 IN
bmAttributes : 0x2 Bulk
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x0
3、USB数据的读写
上面的几行代码仅仅是实现了usb设备的发现,真正要做的是usb数据的读取与写入。此时调试时可以使用BusHould软件在监控usb总线的数据,用于查找解决usb读写过程中的问题。
下面是完整的主机端winusb设备的读写软件:下面代码中向设备发送的数据经过了特定帧格式的编码,winUSB设备接收后解析按此格式的数据进行回复。
import usb.core
import usb.util
import usb.backend.libusb1
import time
winusb = 0x1234
comusb = 0x10c4
mouseusb = 0x46d
dev = usb.core.find(idVendor=winusb)
print(dev)
configuration = dev.get_active_configuration()
dev.set_configuration()
cfg_ = configuration[(0, 0)]
# 0x2 写入节点
outPoint = usb.util.find_descriptor(
cfg_,
# match the first OUT endpoint
custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)
# 0x81 读取节点
inPoint = usb.util.find_descriptor(
cfg_,
# match the first IN endpoint
custom_match = lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN)
#查询版本,型号
msg = [0xa8,0x01,0x02,0x02,0x01,0x00,0x00,0x24]
msg[-1] = sum(msg[1:-1]) & 0xff
r = dev.write(outPoint.bEndpointAddress, msg, 1000)
a= dev.read(inPoint.bEndpointAddress, 1024, 1000)
print("query ack:", end="")
for i in a:
print("%02X "%(i),end="")
print("end")
#启动接收
msg = [0xa8,0x01,0x03,0x02,0x03,0x00,0x05,0x0F,0x00,0x00,0x00,0x00,0x24]
time_stamp = int(time.time()) + 8*3600
msg[-2] = time_stamp & 0xff
msg[-3] = (time_stamp >> 8) & 0xff
msg[-4] = (time_stamp >> 16) & 0xff
msg[-5] = (time_stamp >> 24)& 0xff
msg[-1] = sum(msg[1:-1]) & 0xff
r = dev.write(outPoint.bEndpointAddress, msg, 1000)
a= dev.read(inPoint.bEndpointAddress, 1024, 1000)
print("start ack:", end="")
for i in a:
print("%02X "%(i),end="")
print("end")
for j in range(5):
try:
a= dev.read(inPoint.bEndpointAddress, 1024, 1000)
print("read:", end="")
for i in a:
print("%02X "%(i),end="")
print(" end!")
except usb.core.USBTimeoutError:
pass
except usb.core.USBError:
print("usbError")
break
except Exception as e:
print("read error!",e)
print("send over")
注意此时需要winUSB的设备配合,设备能正常的向主机发送数据,接收数据,主机侧才能正确的进行读写。如果winUSB设备不能正常的向主机发送数据,主机一直读从机设备数据后,读取不到usb主机会自动复位总线。这个问题的原因是从机不能响应主机读取的数据,主机会停止从机,复位USB总线,希望从机能重新正常来发送数据。
正确的解决办法是检测winusb设备的软件代码,让从机能正常的发送数据给主机就可以了。
Device Phase Data Description Cmd.Phase.Ofs(rep)
------ ----- ------------------------------------------------------------------
20.0 CTL 21 0a 00 00 00 00 00 00 SET IDLE 7.1.0
20.0 USTS c0000004 stall pid 7.2.0
4、USB读写异常的处理
dev.read会返回异常,usb.core.USBTimeoutError是超时异常,即没有读到从机的数据,此时可以继续进行读取数据。 usb.core.USBError发生在从机与主机连接断开时,此异常可以识别USB设备断开。
5、产品应用
基于winUSB设备功能实现了lora无线数据协议分析软件,本文以整个软件界面来庆祝winUSB系列博文的结束。
|