python-ivi / python-usbtmc

Provides a USBTMC driver for controlling instruments over USB
MIT License
162 stars 70 forks source link

Agilent U2702A USB scope support #31

Closed susnicek closed 7 years ago

susnicek commented 7 years ago

Dear developer,

I have an usb oscilloscope Agilent U2702A, which should be a USBTMC 488.2 Class device (and probably does not use the SCPI commands). The scope data-sheet says: "Compatible with Microsoft Windows operating systems only. Requires a direct USB connection to the PC so the appropriate driver can be installed in the USB modular instrument." I followed the instructions of using the python-usbtmc package and I tried to operate the device. I was unsuccessful, the device even was not listed as usbtmc device (using the method "list_devices()").

I tried to enable the device in the code (analogously as U2722A/U2723A devices has been added recently). After that the device was detected, but the method "ask" crashed on acquiring the device serial number (the line with "serial = self.device.serial_number"), which ended with "usb.core.USBError: [Errno 32] Pipe error", similarly as in

http://www.eevblog.com/forum/testgear/python-based-instrument-control/50/

My question is: is there any chance that usb oscilloscope Agilent U2702A can work with python-usbtmc package? What should I do for it?

Thank you in advance for you time and an effort to answer!

Best regards, Susnicek

alexforencich commented 7 years ago

Get a wireshark trace of the USB data when the unit is connected to a Windows box with the proper Agilent drivers installed and I'll update python usbtmc accordingly. Or you can help me procure/get access to one of these units so I can debug it myself.

susnicek commented 7 years ago

I did the monitoring work in WinXP using the following steps:

1) I plugged off the usb connector from the PC 2) I started monitoring software USBPcap 3) I plugged on the usb connector into the PC 4) I connected the scope (software-way) in the dedicated Agilent software 5) I enabled channels 1 and 2 in the dedicated Agilent software 6) I disconnected the scope (software-way) in the dedicated Agilent software 7) I plugged off the usb connector from the PC 8) I stopped the monitoring software USBPcap

The monitor log is attached below, but it should be renamed - the correct extension is "pcap". Then it can be opened in Wireshark. I hope there is a minimum of balast in the log. If it helps you: idVendor=0x0957, idProduct=0x2818

out_2.pcap.txt

Best regards, Susnicek

alexforencich commented 7 years ago

Trace looks good, but it's missing the boot-up sequence. Please take another trace, but this time completely power off the U2702A before connecting it to the host. The reason I need this is that the unit (at least for the U2723A that I have, I presume this unit is the same) boots up in what appears to be a firmware update mode and it requires a specific sequence of commands to get out of this mode. Before this is done, the device will have a different idProduct and will not appear as a USBTMC device. The windows driver will check the firmware version when a device in this firmware update mode is connected, update the firmware if necessary, then take the device out of the firmware update mode. I expect to see the device enumerate twice in the trace with two different idProducts. First one will be 0x2818, second one will be 0x2918. You only see the first one and can't talk to the unit via USBTMC as it is still in the firmware update mode. The trace only has 0x2918 as it was previously initialized by the driver before you captured the trace.

susnicek commented 7 years ago

Thanks for the analysis. I hope that this time the trace will tell more. Instead of plugging on/of the USB cable, I plugged on/of the power cord (the USB cable was inserted in the device during monitoring). The monitor trace is here: out_3.pcap.txt

I hope you are right with your predictions!

Best regards, Susnicek

alexforencich commented 7 years ago

Nice, that one has the sequence in it. I will have this sorted out in a few minutes.

alexforencich commented 7 years ago

OK, try the code here: https://github.com/alexforencich/python-usbtmc and let me know what happens.

susnicek commented 7 years ago

I tested the following code:

from usbtmc import usbtmc

print usbtmc.__file__

print usbtmc.list_devices() instr = usbtmc.Instrument(0x0957, 0x2818) print(instr.ask("*IDN?"))

When I run first time, the device clicked silently, but threw the following error code:

/home/*****/Projects/IVI_drivers/USBTMC/usbtmc/usbtmc.py [<DEVICE ID 0957:2818 on Bus 002 Address 006>] Agilent U27xx modular device initialization failed Traceback (most recent call last): File "test.py", line 14, in <module> print(instr.ask("*IDN?")) File "/home/kordik/Projects/IVI_drivers/USBTMC/usbtmc/usbtmc.py", line 716, in ask self.write(message, encoding) File "/home/kordik/Projects/IVI_drivers/USBTMC/usbtmc/usbtmc.py", line 696, in write self.write_raw(str(message).encode(encoding)) File "/home/kordik/Projects/IVI_drivers/USBTMC/usbtmc/usbtmc.py", line 562, in write_raw self.open() File "/home/kordik/Projects/IVI_drivers/USBTMC/usbtmc/usbtmc.py", line 357, in open for cfg in self.device: TypeError: 'NoneType' object is not iterable

When I ran it second (and thrid) time I got following different error: /home/*****/Projects/IVI_drivers/USBTMC/usbtmc/usbtmc.pyc [<DEVICE ID 0957:2918 on Bus 002 Address 007>] Traceback (most recent call last): File "test.py", line 8, in <module> instr = usbtmc.Instrument(0x0957, 0x2818) File "/home/kordik/Projects/IVI_drivers/USBTMC/usbtmc/usbtmc.py", line 288, in __init__ raise UsbtmcException("Device not found", 'init') usbtmc.usbtmc.UsbtmcException: Device not found [init]

Best regards, Susnicek

alexforencich commented 7 years ago

Well, looks like the init worked as the ID changed from 0x2818 to 0x2918. Maybe I should have python-usbtmc try to find the device for a bit longer, though. Try changing the product ID in your script to 0x2918 and try connecting to it again.

susnicek commented 7 years ago

Sorry, I made a mistake, I forgot modify /etc/udev/rules.d/usbtmc.rules with respect to ID 0x2918.

Now, when I plug the device on (using the power cord). The first test is successful, I got the output:

/home/*****/Projects/IVI_drivers/USBTMC/usbtmc/usbtmc.pyc
[<DEVICE ID 0957:2818 on Bus 002 Address 007>]
AGILENT TECHNOLOGIES,U2702A,MY48212052,V2.47-2.05-1.05

However on second script run (without any on/off plugging) the error is still the same, i.e.:

/home/******/Projects/IVI_drivers/USBTMC/usbtmc/usbtmc.pyc
[<DEVICE ID 0957:2918 on Bus 002 Address 008>]
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    instr =  usbtmc.Instrument(0x0957, 0x2818)
  File "/home/******/Projects/IVI_drivers/USBTMC/usbtmc/usbtmc.py", line 288, in __init__
    raise UsbtmcException("Device not found", 'init')
usbtmc.usbtmc.UsbtmcException: Device not found [init]

Best regards, Susnicek

alexforencich commented 7 years ago

You need to change your test.py to look for 0x2918 instead of 0x2818.

instr =  usbtmc.Instrument(0x0957, 0x2818)

should be

instr =  usbtmc.Instrument(0x0957, 0x2918)
susnicek commented 7 years ago

Thanks, it works with 0x2918, but only on second or more time run. When device plugged on (the power), the script runs only with 0x2818. Is it possible to work around in usbtmc.py?

Best regards, Susnicek

alexforencich commented 7 years ago

Whoops; got the IDs mixed up on one check. Try the latest code.

susnicek commented 7 years ago

Sorry, it seems to me that it works as previously: With 0x2818 it works only on first run. With 0x2918 it works on succeeding runs.

When I run the test on first time (with device just powered on) with 0x2918 it fails on line 288 (see above). When I run it second time with 0x2918 it fails again - on line 288. Again, after that when I run the test with 0x2818, I succeeds (it takes longer time to initialize). Then when I run the test again with 0x2818, It does not work - it gives the same error on line 288. To be successful after the initialization it needs ID 0x2918.

Thank you very much for your effort! Best regards, Susnicek

alexforencich commented 7 years ago

Can you post the output of your test script using id 0x2918 and a cold boot of the U2702A? And you're sure you're using the latest code?

susnicek commented 7 years ago

I use the latest version of usbtmc - v0.8 (installed via pip the day before yesterday). Maybe, the problem is that in case of U2702A the ID is smaller 0x2818 in update mode (comparing to 0x2918 in normal mode). ... and in case of U2722A the ID is greater 0x4418 in update mode (comparing to 0x4318 in normal mode). Therefore, analogous code modification can be error prone. I tried to modify the usbtmc.py file accordingly, see below.

Furthermore I needed to comment the lines 168 and 169, to get it work. But I do not know why the lines 168 and 169 need be commented. Maybe, you will get into the problem deeper.

usbtmc.py.txt

I used the following code to test it:


from usbtmc import usbtmc
import time

print usbtmc.__file__

print usbtmc.list_devices()
instr =  usbtmc.Instrument(0x0957, 0x2818)
print(instr.ask("*IDN?"))

The next step will be to test other commands than "*IDN?". I think there will be other difficulties...

Best regards, Susnicek

alexforencich commented 7 years ago

You need to use the idVendor/idProduct of the unit after the boot sequence. The idea behind the code in usbtmc.py is that if you specify 0x2918, it will also grab a device at 0x2818 and initialize it to 0x2918 before using it. Once the device is initialized, it appears as a USBTMC device and no special filter exceptions are required. Do not comment out lines 168 and 169, that completely disables the PID/VID filter and unconditionally accepts the first detected device.

Are you sure that you are using the latest code from git? The version in PIP is missing the required changes. You actually don't even have to install python-usbtmc to test a new version; just clone this repo, copy your test.py into the root of the repo, and run it from there - it will use the code in the repo instead of the installed version. I have triple checked all of the conditionals and they all look correct now. So please test the code in the repo, use VID/PID 0x0957/0x2918 to connect to the device in your script, and post the full output so I can try to figure out what's going on.

susnicek commented 7 years ago

Today I work at home where no pip version of usbtmc is installed. I cloned the git version of usbtmc and ran the test from the usbtmc root directory. The result is the same, after device power on and using VID/PID 0x0957/0x2918 in test.py script I got this:

/home/****/Projects/IVI_drivers/python-usbtmc-master/usbtmc/usbtmc.py
[<DEVICE ID 0957:2818 on Bus 001 Address 007>]
Traceback (most recent call last):
  File "test.py", line 7, in <module>
    instr =  usbtmc.Instrument(0x0957, 0x2918)
  File "/home/****/Projects/IVI_drivers/python-usbtmc-master/usbtmc/usbtmc.py", line 288, in __init__
    raise UsbtmcException("Device not found", 'init')
usbtmc.usbtmc.UsbtmcException: Device not found [init]

However if I use VID/PID 0x0957/0x2818 it works, but only once. To be succesfull at the second (and more) time I need to use VID/PID 0x0957/0x2918.

Best regards, Susnicek

alexforencich commented 7 years ago

Ah, found the problem. The if on line 163 should be an elif. Whoops. I will commit that change in the morning.

susnicek commented 7 years ago

Yes, that is it! Now it works with VID/PID 0x0957/0x2918. But, there is slight problem during the first run (after power on): the program shows the IDN correctly but never ends (I need to end it using Ctrl+C). Next runs work perfectly. Maybe it is a distro-related problem (now I am at Archlinux), I will test it on monday on Xubuntu at work.

Best regards, Susnicek

alexforencich commented 7 years ago

Yeah, that's a separate issue with pyusb.

susnicek commented 7 years ago

Thank you for resolving the problem. Please, just give me a last advice:

The only programmer guide for the instruments U2702/1A is following:

U2702A_programmer_guide.pdf

In the guide there are code examples with IVI functions only. My question is: Shall I use the SCPI commands for the scope control? There is some table with SCPI commands in the document, but no examples... Or is it better to use python-ivi package and create my own class for this scope according the instructions here?

Best regards, Susnicek

alexforencich commented 7 years ago

Yeah, that unit is extremely lacking in terms of documentation. Python-ivi just wraps up the SCPI commands with a decent API, with the intention of being able to swap out different instruments. So start with just figuring out what the commands are, then go write a driver for python-ivi if you want to. I think you may need to resort to using wireshark to figure out what commands are actually getting sent to the scope as the documentation doesn't seem to cover the SCPI commands at all.

susnicek commented 7 years ago

Ok, thank you very much for the advice. Now, I think the issue can be closed.

Best regards, Susnicek