PyUSB:与 OWON 示波器的 SCPI 通信

新手上路,请多包涵

这是一个更新和缩短的问题。

通过 PyUSB 与 USB 设备通信应该很容易。所以,我正在尝试在 Win10 下使用 PyUSB 从 USB 设备(示波器)读取数据。显然,USB 驱动程序 (libusb-win32 v1.2.6.0) 已正确安装,因为已找到设备并且我从 print(dev) 得到了一些响应(见下文)。从这里我可以看到输出端点地址是 0x3 输入端点地址是 0x81

根据 示波器手册,我应该发送 :SDSLSCPI# 到设备以将其设置为 SCPI 模式,并且应该得到响应“:SCPION”。但是,当发送 :SDSLSCPI# 时,示波器的监视器可重复地冻结并重新启动。

如果我发送 *IDN? 我应该得到响应 ,P1337,1842237,V2.4.0-> 。但前提是设备已经处于 SCPI 模式。显然,它不是,我收到超时错误(见下文)。

那么,我在这里做错了什么? PyUSB 教程 中缺少哪些信息。我是否使用了错误的 PyUSB 命令/参数,或者是关于缺少额外的驱动程序,还是关于硬件,Win10 或设备硬件?感谢您提供有关如何找出问题所在的提示。

顺便说一句, dev.read(0x81,7) 中的第二个值是多少?要读取的字节数?好吧,通常我不知道设备会发送多少字节。我期待一个命令在超时时间内读取直到换行符或其他一些终止符。我在哪里可以找到关于 PyUSB 的“万无一失”的文档、教程和示例?

代码:

 import usb.core
import usb.util

dev = usb.core.find(idVendor=0x5345, idProduct=0x1234)
if dev is None:
    raise ValueError('Device is not found')
# device is found :-)
print(dev)

dev.set_configuration()

msg = ':SDSLSCPI#'
print("Write:", msg, dev.write(3,msg))

print("Read:", dev.read(0x81,7))

来自 print(dev) 的输出:

 DEVICE ID 5345:1234 on Bus 000 Address 001 =================
 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               : 0x5345
 idProduct              : 0x1234
 bcdDevice              :  0x294 Device 2.94
 iManufacturer          :    0x1 System CPU
 iProduct               :    0x2 Oscilloscope
 iSerialNumber          :    0x3 SERIAL
 bNumConfigurations     :    0x1
  CONFIGURATION 1: 500 mA ==================================
   bLength              :    0x9 (9 bytes)
   bDescriptorType      :    0x2 Configuration
   wTotalLength         :   0x20 (32 bytes)
   bNumInterfaces       :    0x1
   bConfigurationValue  :    0x1
   iConfiguration       :    0x5 Bulk Data Configuration
   bmAttributes         :   0xc0 Self Powered
   bMaxPower            :   0xfa (500 mA)
    INTERFACE 0: Physical ==================================
     bLength            :    0x9 (9 bytes)
     bDescriptorType    :    0x4 Interface
     bInterfaceNumber   :    0x0
     bAlternateSetting  :    0x0
     bNumEndpoints      :    0x2
     bInterfaceClass    :    0x5 Physical
     bInterfaceSubClass :    0x6
     bInterfaceProtocol :   0x50
     iInterface         :    0x4 Bulk Data Interface
      ENDPOINT 0x81: Bulk IN ===============================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :   0x81 IN
       bmAttributes     :    0x2 Bulk
       wMaxPacketSize   :  0x200 (512 bytes)
       bInterval        :    0x0
      ENDPOINT 0x3: Bulk OUT ===============================
       bLength          :    0x7 (7 bytes)
       bDescriptorType  :    0x5 Endpoint
       bEndpointAddress :    0x3 OUT
       bmAttributes     :    0x2 Bulk
       wMaxPacketSize   :  0x200 (512 bytes)
       bInterval        :    0x0

错误信息:

 Traceback (most recent call last):
  File "Osci.py", line 15, in <module>
    print("Read:", dev.read(0x81,7))
  File "C:\Users\Test\Programs\Python3.7.4\lib\site-packages\usb\core.py", line 988, in read
    self.__get_timeout(timeout))
  File "C:\Users\Test\Programs\Python3.7.4\lib\site-packages\usb\backend\libusb0.py", line 542, in bulk_read
    timeout)
  File "C:\Users\Test\Programs\Python3.7.4\lib\site-packages\usb\backend\libusb0.py", line 627, in __read
    timeout
  File "C:\Users\Test\Programs\Python3.7.4\lib\site-packages\usb\backend\libusb0.py", line 431, in _check
    raise USBError(errmsg, ret)
usb.core.USBError: [Errno None] b'libusb0-dll:err [_usb_reap_async] timeout error\n'

更新:

我收到了供应商的回复。他确认示波器(或至少这个特定系列)在发送命令时崩溃 :SDSLSCPI# 。他将联系下周返回的开发商。好的,到目前为止,我似乎没有机会让它与这个特定的设备和可用的文档一起运行:-(。

原文由 theozh 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

我想除非有人已经遇到过同样的问题,否则 没有机会 回答这个问题。对于花时间提出帮助建议的所有人(@Alex P.、@Turbo J、@igrinis、@2xB),我深表歉意。

我的发现:( 我希望它们对其他人有用):

  1. PyUSB 似乎一切正常。
  2. 供应商提供了过时和错误的文件。我非常希望他们能尽快更新他们主页上的文档。
  3. 发送命令 :SDSLSCPI# 不需要进入 SCPI 模式(但实际上会导致崩溃/重启)
  4. 例如: :CHAN1:SCAL 10v 是错误的,它必须是 :CH1:SCALe 10v (显然 不能 缩写命令,尽管在文档中提到 :CH1:SCAL 10v 也应该工作。 )
  5. 手册中缺少获取数据的基本命令 :DATA:WAVE:SCREen:CH1?

它为我工作的方式(到目前为止):

以下是我期望供应商/制造商提供的最少代码。但相反,我浪费了很多时间来调试他们的文档。然而,仍然有一些奇怪的事情发生,例如,似乎只有在事先请求标头的情况下才能获得数据。但是,好吧,这不是原始问题的主题。

代码:

 ### read data from a Peaktech 1337 Oscilloscope (OWON)
import usb.core
import usb.util

dev = usb.core.find(idVendor=0x5345, idProduct=0x1234)

if dev is None:
    raise ValueError('Device not found')
else:
    print(dev)
    dev.set_configuration()

def send(cmd):
    # address taken from results of print(dev):   ENDPOINT 0x3: Bulk OUT
    dev.write(3,cmd)
    # address taken from results of print(dev):   ENDPOINT 0x81: Bulk IN
    result = (dev.read(0x81,100000,1000))
    return result

def get_id():
    return send('*IDN?').tobytes().decode('utf-8')

def get_data(ch):
    # first 4 bytes indicate the number of data bytes following
    rawdata = send(':DATA:WAVE:SCREen:CH{}?'.format(ch))
    data = []
    for idx in range(4,len(rawdata),2):
        # take 2 bytes and convert them to signed integer using "little-endian"
        point = int().from_bytes([rawdata[idx], rawdata[idx+1]],'little',signed=True)
        data.append(point/4096)  # data as 12 bit
    return data

def get_header():
    # first 4 bytes indicate the number of data bytes following
    header = send(':DATA:WAVE:SCREen:HEAD?')
    header = header[4:].tobytes().decode('utf-8')
    return header

def save_data(ffname,data):
    f = open(ffname,'w')
    f.write('\n'.join(map(str, data)))
    f.close()

print(get_id())
header = get_header()
data = get_data(1)
save_data('Osci.dat',data)
### end of code

结果:( 使用 gnuplot)

在此处输入图像描述

原文由 theozh 发布,翻译遵循 CC BY-SA 4.0 许可协议

首先请注意,@igrinis 发布了一段视频,展示了您想要达到的目标。

(如@igrinis 所述:)对于 read(...) 中的第二个值,理论上您是正确的。好消息是,您几乎可以经常请求更长的答案。因此,请尝试请求 256 个字节,看看是否可以修复您当前的代码。

如果这不能解决您的问题:

您可以尝试在第二台 PC/笔记本电脑周围安装能够与设备通信的制造商提供的软件,并使用 Wireshark(安装了 USBPcap)来读取设备通信。发送和接收的 USB 批量数据写入 Wiresharks 的“Leftover Capture Data”字段。通过查看,您可以比较您的脚本发送的内容以及它应该如何发现错误。您可以通过右键单击并选择“应用为列”将其作为列添加到数据包列表中。例如,您的问题可能是将命令编码为大端或小端。

PyUSB 的文档:

[更新] 为已经给出了一些答案和更多内容的精彩评论添加了提示。

原文由 2xB 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏