# Basic Script

This script shows a few commonly-used programming steps.

## Example Script

basics.py

    #!python3

    """This program illustrates a few commonly-used programming
    features of your Infiniium XR8 oscilloscope.
    """

    # Import modules.
    import pyvisa
    import struct
    import sys
    import platformdirs

    # Global variables.
    # oscilloscope_visa_address = "TCPIP0::lab-pyr-p2-13.cos.is.keysight.com::inst0::INSTR"
    oscilloscope_visa_address = "TCPIP0::localhost::hislip0,4880::INSTR"
    timeout = 20000  # 20 seconds.
    scope_base_directory = "%USER_DATA_DIR%\\"
    local_base_directory = f"{platformdirs.user_documents_dir()}\\"

    def initialize():
        """Initialize:"""

        # Clear status.
        Infiniium.write("*CLS")

        # Get and display the device's *IDN? string.
        idn_string = Infiniium.query("*IDN?").strip()
        print(f"Identification string: '{idn_string}'")

        # Load the default setup.
        Infiniium.write("*RST")

        # Stop acquisitions and clear the display.
        Infiniium.write(":ACQuire:STOP")
        Infiniium.write(":ACQuire:CDISplay")

    def set_up():
        """Set up:"""

        # Set probe attenuation factor.
        # Infiniium.write(":CHANnel1:PROBe:DB 1.0")
        qresult = Infiniium.query(":CHANnel1:PROBe:DB?").strip()
        print(f"Channel 1 probe attenuation factor: {qresult}")

        # Use auto-scale to automatically set up oscilloscope.
        print("Autoscale.")
        Infiniium.query(":SYSTem:AUToscale;*OPC?")

        # Stop acquisitions and clear the display.
        Infiniium.write(":ACQuire:STOP")
        Infiniium.write(":ACQuire:CDISplay")

        # Set trigger mode.
        Infiniium.write(":TRIGger:MODE EDGE")
        qresult = Infiniium.query(":TRIGger:MODE?").strip()
        print(f"Trigger mode: {qresult}")

        # Set EDGE trigger parameters.
        Infiniium.write(":TRIGger:EDGE:SOURce CHANnel1")
        qresult = Infiniium.query(":TRIGger:EDGE:SOURce?").strip()
        print(f"Trigger edge source: {qresult}")

        Infiniium.write(":TRIGger:CHANnel1:LEVel 150E-3")
        qresult = Infiniium.query(":TRIGger:CHANnel1:LEVel?").strip()
        print(f"Trigger level, channel 1: {qresult}")

        Infiniium.write(":TRIGger:EDGE:SLOPe POSitive")
        qresult = Infiniium.query(":TRIGger:EDGE:SLOPe?").strip()
        print(f"Trigger edge slope: {qresult}")

        # Save oscilloscope setup.
        setup_file = f"{scope_base_directory}setup.seti"
        Infiniium.write(f':DISK:SETup:SAVE "{setup_file}"')
        print(f"Setup saved to: {setup_file}")

        # Change oscilloscope settings with individual commands:

        # Set vertical scale and offset.
        Infiniium.write(":CHANnel1:YSCale 0.1")
        qresult = float(Infiniium.query(":CHANnel1:YSCale?"))
        print(f"Channel 1 vertical scale: {qresult:f}")

        Infiniium.write(":CHANnel1:YOFFset 0.0")
        qresult = float(Infiniium.query(":CHANnel1:YOFFset?"))
        print(f"Channel 1 offset: {qresult:f}")

        # Set horizontal scale and offset.
        Infiniium.write(":TIMebase:SCALe 200e-6")
        qresult = Infiniium.query(":TIMebase:SCALe?").strip()
        print(f"Timebase scale: {qresult}")

        Infiniium.write(":TIMebase:POSition 0.0")
        qresult = Infiniium.query(":TIMebase:POSition?").strip()
        print(f"Timebase position: {qresult}")

        # Set the acquisition mode.
        Infiniium.write(":ACQuire:SMODe NORMal")
        qresult = Infiniium.query(":ACQuire:SMODe?").strip()
        print(f"Acquire mode: {qresult}")

        # Or, set up oscilloscope by loading a previously saved setup.
        Infiniium.write(f':DISK:SETup:RECall "{setup_file}"')
        print(f"Setup recalled from: {setup_file}")

    def capture():
        """Capture:"""

        # Set the desired number of waveform points,
        # and capture an acquisition.
        Infiniium.write(":ACQuire:POINts:AUTO OFF")
        Infiniium.write(":ACQuire:POINts 2048")
        Infiniium.write(":TIMebase:INTerpolate:AUTO OFF")
        Infiniium.write(":TIMebase:INTerpolate:METHod NONE")
        Infiniium.query(":ACQuire:SINGle;*OPC?")

    def analyze():
        """Analyze:"""

        # Make measurements.
        Infiniium.write(":MEASure:HORizontal:FREQuency:SOURce CHANnel1")
        qresult = Infiniium.query(":MEASure:HORizontal:FREQuency:SOURce?").strip()
        print(f"Measure horizontal frequency source: {qresult}")

        Infiniium.write(":MEASure:HORizontal:FREQuency")
        qresult = Infiniium.query(":MEASure:HORizontal:FREQuency?").strip()
        print(f"Measured frequency on channel 1: {qresult}")

        Infiniium.write(":MEASure:VERTical:VAMPlitude:SOURce CHANnel1")
        qresult = Infiniium.query(":MEASure:VERTical:VAMPlitude:SOURce?").strip()
        print(f"Measure vertical amplitude source: {qresult}")

        Infiniium.write(":MEASure:VERTical:VAMPlitude")
        qresult = Infiniium.query(":MEASure:VERTical:VAMPlitude?").strip()
        print(f"Measured vertical amplitude on channel 1: {qresult}")

        # Download the screen image.
        screen_bytes = Infiniium.query_binary_values(
            ":DISPlay:DATA? PNG", datatype="s", container=bytes
        )

        # Save display data values to file.
        image_file = f"{local_base_directory}screen_image.png"
        f = open(image_file, "wb")
        f.write(screen_bytes)
        f.close()
        print(f"Screen image written to {image_file}.")

        # Download waveform data.

        # Get the waveform type.
        qresult = Infiniium.query(":ACQuire:SMODe?").strip()
        print(f"Waveform type: {qresult}")

        # Get the number of waveform points.
        qresult = Infiniium.query(":WAVeform:YFORmat:POINts?").strip()
        print(f"Waveform points: {qresult}")

        # Set the waveform source.
        Infiniium.write(":WAVeform:SOURce CHANnel1")
        qresult = Infiniium.query(":WAVeform:SOURce?").strip()
        print(f"Waveform source: {qresult}")

        # Specify the byte order in WORD data.
        Infiniium.write(":SYSTem:BORDer LENDian")
        qresult = Infiniium.query(":SYSTem:BORDer?").strip()
        print(f"Waveform byte order for WORD data: {qresult}")

        # Get numeric values for later calculations.
        x_increment = float(Infiniium.query(":WAVeform:YFORmat:XINCrement?"))
        print(f"Waveform X increment: {x_increment:f}")
        x_origin = float(Infiniium.query(":WAVeform:YFORmat:XORigin?"))
        print(f"Waveform X origin: {x_origin:f}")
        y_increment = float(Infiniium.query(":WAVeform:YFORmat:WORD:ENCoding:YINCrement?"))
        print(f"Waveform Y increment: {y_increment:f}")
        y_origin = float(Infiniium.query(":WAVeform:YFORmat:WORD:ENCoding:YORigin?"))
        print(f"Waveform Y origin: {y_origin:f}")

        # Get the waveform data.
        # Infiniium.write(":WAVeform:STReaming OFF")
        data_bytes = Infiniium.query_binary_values(
            ":WAVeform:YFORmat:WORD:YDATa?", datatype="s", container=bytes
        )
        data_bytes_length = len(data_bytes)
        print(f"Byte count: {data_bytes_length}")

        block_points = data_bytes_length / 2

        # Unpack or split into list of data values.
        values = struct.unpack("%dh" % block_points, data_bytes)
        print(f"Number of data values: {len(values)}")

        # Save waveform data values to CSV file.
        wfm_data_file = f"{local_base_directory}waveform_data.csv"
        f = open(wfm_data_file, "w")

        for i in range(0, len(values) - 1):
            time_val = x_origin + (i * x_increment)
            voltage = (values[i] * y_increment) + y_origin
            f.write(f"{time_val:E}, {voltage:f}\n")

        f.close()
        print(f"Waveform format WORD data written to {wfm_data_file}.")

    def exit_program():
        """Exit program."""

        # Close connection to oscilloscope.
        sys.stdout.write("Closing oscilloscope connection.\n")
        Infiniium.write(":SYSTem:GTLocal")  # Unlock GUI.
        Infiniium.clear()  # Clear oscilloscope communications interface.
        Infiniium.close()  # Close communications interface to oscilloscope.
        rm.close()  # Close resource manager.
        print("End of program.")
        sys.exit()

    def check_error_queue(when):
        """Check error queue."""

        errors_found = False
        while True:
            # Keep reading errors until "No error".
            error_string = Infiniium.query(":SYSTem:ERRor:NEXT? DIAGnostic")
            if error_string:  # If there is an error string value.

                if error_string.find("0,", 0, 2) == -1:  # Not "No error".
                    errors_found = True
                    print(f"ERROR: {error_string}")

                else:  # "No error"
                    break

            else:  # :SYSTem:ERRor:NEXT? DIAGnostic should always return string.
                errors_found = True
                print("ERROR: :SYSTem:ERRor:NEXT? DIAGnostic returned nothing.")
                break

        if errors_found:
            print(f"Exited because error(s) found when: '{when}'")
            exit_program()

    # ==========================================================
    # Main program:
    # ==========================================================

    # Connect and initialize oscilloscope.
    rm = pyvisa.ResourceManager("C:\\Windows\\System32\\visa64.dll")
    try:
        Infiniium = rm.open_resource(oscilloscope_visa_address)
    except Exception:
        print(
            f"Unable to connect to oscilloscope at {oscilloscope_visa_address}. Aborting program."
        )
        sys.exit()

    Infiniium.timeout = timeout  # Set global timeout.
    Infiniium.clear()  # Clear the instrument bus.
    # Lock GUI happens automatically.

    # Initialize the oscilloscope, capture data, and analyze.
    initialize()
    set_up()
    capture()
    analyze()

    # Check error queue.
    check_error_queue("End of program")

    # Exit program.
    exit_program()