pyvisa / pyvisa

A Python package with bindings to the "Virtual Instrument Software Architecture" VISA library, in order to control measurement devices and test equipment via GPIB, RS232, or USB.
https://pyvisa.readthedocs.io
MIT License
796 stars 248 forks source link

[COM] Communication issue with pyvisa using HP35889A #759

Closed deolHeia closed 1 year ago

deolHeia commented 1 year ago

Hi,

I don’t understand that :

I have a device HP 3589A and a GPIB-USB-HS. I need to simulate a printer on GPIB bus (Its work in VisualBasic).

The simple code is :

import pyvisa
from pyvisa import constants as pyvisaConstants

rm = pyvisa.ResourceManager()
device = rm.open_resource("GPIB0::19::INSTR")
device.write("PRINT:ADDRESS ASRL3::INSTR")

device.timeout = 20000

device.write("*CLS")              # Clear the STATUS BYTE register
device.write("*ESE 1")            # Bit 1 = OPERATION COMPLETE
device.write("*SRE 32")           # Bit 5 = EVENT_STATUS
device.write("*PCB ASRL3::INSTR") # Set up Pass Control back address
device.write("*WAI")              # Ensure all pending operations done

device.write("PRINt:DUMP:ALL")    # print the screen
device.write("*OPC")              # Set OPC bit when everything complete

# Give control of the bus to the 3589A
device.visalib.gpib_pass_control(device.session, 19, pyvisaConstants.VI_NO_SEC_ADDR)

rm.close()

I don’t understand where is this session? How I pass the controll to GPIB-USB-HS after "printing"?

The traceback is:

Traceback (most recent call last):

  File ~\switchdrive\GEEL-SIU\11_bricolage\GPIB\PyRemoteCtrl\HMI\untitled0.py:25 in <module>
    device.visalib.gpib_pass_control(device.session, 19, pyvisaConstants.VI_NO_SEC_ADDR)

  File ~\Anaconda3\envs\GEEL_py39\lib\site-packages\pyvisa\ctwrapper\functions.py:960 in gpib_pass_control
    return library.viGpibPassControl(session, primary_address, secondary_address)

  File ~\Anaconda3\envs\GEEL_py39\lib\site-packages\pyvisa\ctwrapper\highlevel.py:226 in _return_handler
    return self.handle_return_value(session, ret_value)  # type: ignore

  File ~\Anaconda3\envs\GEEL_py39\lib\site-packages\pyvisa\highlevel.py:251 in handle_return_value
    raise errors.VisaIOError(rv)

VisaIOError: VI_ERROR_NSUP_OPER (-1073807257): The given session or object reference does not support this operation.

Cann you help me? I have no documentation of this session found.

Instrument details

Output of pyvisa-info

Machine Details:
   Platform ID:    Windows-10-10.0.22000-SP0
   Processor:      Intel64 Family 6 Model 158 Stepping 9, GenuineIntel

Python:
   Implementation: CPython
   Executable:     C:\Users\andeol.demierre\Anaconda3\envs\GEEL_py39\python.exe
   Version:        3.9.12
   Compiler:       MSC v.1916 64 bit (AMD64)
   Bits:           64bit
   Build:          Apr  4 2022 05:22:27 (#main)
   Unicode:        UCS4

PyVISA Version: 1.13.0

Backends:
   ivi:
      Version: 1.13.0 (bundled with PyVISA)
      #1: C:\WINDOWS\system32\visa32.dll:
         found by: auto
         bitness: 64
         Vendor: National Instruments
         Impl. Version: 24118016
         Spec. Version: 7340032
      #2: C:\WINDOWS\system32\visa64.dll:
         found by: auto
         bitness: 64
         Vendor: National Instruments
         Impl. Version: 24118016
         Spec. Version: 7340032
   py:
      Version: 0.6.3
      ASRL INSTR: Available via PySerial (3.5)
      USB INSTR: Available via PyUSB (1.2.1). Backend: libusb1
      USB RAW: Available via PyUSB (1.2.1). Backend: libusb1
      TCPIP INSTR: Available
         Resource discovery:
         - VXI-11: ok
         - hislip: ok
      VICP INSTR:
         Please install PyVICP to use this resource type.
      TCPIP SOCKET: Available
      GPIB INSTR:
         Please install linux-gpib (Linux) or gpib-ctypes (Windows, Linux) to use this resource type. Note that installing gpib-ctypes will give you access to a broader range of funcionality.
         No module named 'gpib'
arr-ee commented 1 year ago

You should be able to just call device.pass_control(19, pyvisaConstants.VI_NO_SEC_ADDR), visalib is not really intended to be called manually.

Session here is a VISA session identifier: https://www.ni.com/docs/en-US/bundle/ni-visa/page/ni-visa/communicationchannelssessions.html

Error is coming from the VISA library — would you mind sharing the version that worked in VB?

arr-ee commented 1 year ago

BTW this is the VISA function being called by pyvisa, with signature being identical (type differences aside). Were you using some other way of doing the same in VB?

deolHeia commented 1 year ago

Ok it is not the same function. In VB the function used from DLL is:

Dim usbGPBIController As VisaComLib.IGpibIntfc
…
usbGPBIController.PassControl (ScopeAdr)

But that is possible: I search in wrong place. With windows 10 the package NI-VISA it's work. In Windows 11, I need add package NI-488 to GPIB-USB-HS work.

With psvisa can I found the VISA session? Need I use another function to call this inverting of bus? With pyvisa, it’s Possible to use the secondary address of the GPIB-USB-HS to create a simple listener?

Ref NI-VISA driver : https://www.ni.com/fr-ch/support/downloads/drivers/download.ni-visa.html#480875 REF NI-488 driver: https://www.ni.com/fr-ch/support/downloads/drivers/download.ni-488-2.html#467646 Ref LabView PassControl : https://www.ni.com/docs/fr-FR/bundle/labview/page/lvinstio/passcontrol.html

arr-ee commented 1 year ago

With psvisa can I found the VISA session?

You should not need it, calling device.pass_control(19, pyvisaConstants.VI_NO_SEC_ADDR) instead should work.

With pyvisa, it’s Possible to use the secondary address of the GPIB-USB-HS to create a simple listener?

pyvisa wraps underlying VISA driver (NI one in your case), but specific functionality exposed through python interface might not match the driver completely. One way to check is to locate the required function name in NI’s docs, then look it up in this repo (github search works fine for this).

deolHeia commented 1 year ago

Sorry I have not transphert this information : device.pass_control(19, pyvisaConstants.VI_NO_SEC_ADDR) not working

Traceback (most recent call last):
  File "D:\PyRemoteCtrl\HMI\examples\testPassControl.py", line 26, in <module>
    device.pass_control(19, pyvisaConstants.VI_NO_SEC_ADDR)
    ^^^^^^^^^^^^^^^^^^^
AttributeError: 'GPIBInstrument' object has no attribute 'pass_control'

I have test with Spider and a native python.

Thank you from all information. If I found anything, I write that here.

arr-ee commented 1 year ago

Apologies, this was my mistake — I have not read the code closely enough.

To use pass_control, you need to open the interface itself, like so:

iface = rm.open_resource('GPIB0::INTFC')
iface.pass_control(19, pyvisaConstants.VI_NO_SEC_ADDR)

If I got it right, iface would be a GPIBInterface object that should also have the regular read etc methods to allow for being a listener. However, I have zero first-hand experience with native GPIB so this is just theories based on existing code.

See also: https://pyvisa.readthedocs.io/en/latest/api/resources.html#pyvisa.resources.GPIBInterface & https://github.com/pyvisa/pyvisa/blob/main/pyvisa/resources/gpib.py#L94

deolHeia commented 1 year ago

Hi,

It’s work !

Thank you from the help.

If anythink woldlike a virtual printer, I post the code :

import time
from pyvisa import ResourceManager, constants
from PIL import Image

# bit mask
translator = bytes([1, 2, 4, 8, 16, 32, 64, 128])

def converter(rawPixel):
    # PCL format has one bit per pixel and pilloy understand only bytes
    convPixel = bytearray()
    for i in range(7, -1, -1):
        if rawPixel >> i & 1:
            convPixel.append(1)
        else:
            convPixel.append(255)
    return bytes(convPixel)

def PCLtoBMP(datas):
    # PCL format has one heder and N lines

    image        = b''          # Image buffer
    datasLen     = len(datas)   # Size of file
    i            = 0            # position in file
    lineHeader   = False        # line header reading ?
    getLine      = 0            # number of byte to get a line
    lineNumber   = 0            # work on line 
    bytesPerLine = 0            # stock bytes per line

    while i < datasLen:
        if getLine > 0:
            # line header ended => read a line
            image = image + converter(datas[i])
            getLine = getLine -1
            i = i + 1

        elif datas[i] == 27 and datas[i+1] == 42 and datas[i+2] == 98:
            # A line header in PCL is coded : [ESCAPE]*b[image line]W
            # in numbers : 27, 42, 98, #, #, ..., #, #, 87
            lineHeader   = True
            headerBuffer = bytearray(b'')
            i = i + 3

        elif lineHeader == True:
            # End of line header => compute the number of byte to read
            if datas[i] == 87:
                bytesPerLine = int(headerBuffer.decode('utf-8'))
                getLine    = bytesPerLine
                lineNumber = lineNumber + 1
                lineHeader  = False

            else:
                # Read the line header
                headerBuffer.append(datas[i])
            i = i + 1

        else:
            # anothers datas (file header, end of file, ...)
            i = i + 1

    return (bytesPerLine * 8, lineNumber), image

rm = ResourceManager()

listOfRessources = rm.list_resources('?*')
print(listOfRessources)

gpibUsbHi        = None
for r in listOfRessources:
    if "INTFC" in r:
        gpibUsbHi = r

iface = rm.open_resource(gpibUsbHi)

device = rm.open_resource("GPIB0::19::INSTR")
device.write("*IDN?")
infos = device.read()
print(infos)

device.timeout = 20000

device.write("PRINt:ADDRess {}".format(0))

device.write("*CLS")              # Clear the STATUS BYTE register
device.write("*ESE 1")            # Bit 1 = OPERATION COMPLETE
device.write("*SRE 32")           # Bit 5 = EVENT_STATUS
device.write("*PCB {}".format(0)) # Set up Pass Control back address
device.write("*WAI")              # Ensure all pending operations done

device.write("PRINt:DUMP:ALL")    # print the screen
device.write("*OPC")              # Set OPC bit when everything complete

time.sleep(6)

iface = rm.open_resource(gpibUsbHi)
iface.pass_control(19, constants.VI_NO_SEC_ADDR)

time.sleep(2)

datas = iface.read_bytes(26419) # 26419 = 11 [HEAD] + 400 * 480 [image] pixels
size, image = PCLtoBMP(datas)

imtest = Image.frombytes("L", size, image)
imtest.show()
imtest.save("screen.png")

# close and reopen the device to become master
device.close()

device = rm.open_resource("GPIB0::19::INSTR")

device.write("Create error on display")