Program Fact 3. To Create a Hardware Diagram

The following Python script creates an example Hardware Diagram using a Keysight N7734A optical switch. The script uses the :CONFigure SCPI subsystem to create the Hardware Diagram. Notice that the visa address uses hislip0.

Copy
Hardware Diagram Program
#******************************************************************************
#    MIT License
#    Copyright(c) 2023 Keysight Technologies
#    Permission is hereby granted, free of charge, to any person obtaining a copy
#    of this software and associated documentation files (the "Software"), to deal
#    in the Software without restriction, including without limitation the rights
#    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#    copies of the Software, and to permit persons to whom the Software is
#    furnished to do so, subject to the following conditions:
#    The above copyright notice and this permission notice shall be included in all
#    copies or substantial portions of the Software.
#    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#    SOFTWARE.
#******************************************************************************

import pyvisa as visa  # import VISA library

visa_address = 'TCPIP0::localhost::hislip0,4880::INSTR'  # Edit as needed
# Switch module name required for :CONFigure:PORT:CONNect command arguments
SWITCHES = ['"N7734A"']  # switch name
DCAM_MODELS = ['N1092A']
# station number keys, DUT fixture name values
FIXTURES = {'1': '"Test Station 1"', '2': '"Test Station 2"'}  # station number keys, DUT fixture name values
LANE_CNT = 4
STATION_CNT = 2


class NoModuleException(Exception):
    """ Exception handler when a DCA-M module is not found. """
    pass


class NoSwitchException(Exception):
    """ Exception handler when a switch is not found. """
    pass


def open_connection(address):
    """ Opens visa connection FlexOTO. """
    print('Connecting to FlexOTO Hardware Diagram ...')
    try:
        rm = visa.ResourceManager()
        connection = rm.open_resource(address)
        connection.timeout = 5000  # Set connection timeout to s
        connection.read_termination = '\n'
        connection.write_termination = '\n'
        inst_id = connection.query('*IDN?')
        print('\nFlexOTO connection established to:\n\t' + inst_id, flush=True)
        connection.write(':SYSTem:DEFault')
        connection.query('*OPC?')
    except (visa.VisaIOError, visa.InvalidSession):
        print('\nVISA ERROR: Cannot open instrument address.\n', flush=True)
    except Exception as other:
        print('\nVISA ERROR: Cannot connect to instrument:', other, flush=True)
        print('\n')
    return connection


def place_switches_on_switch_diagram(hwdgm, switches):
    timeout = hwdgm.timeout
    hwdgm.timeout = 10000
    hwdgm.write(':SWITch:DMEThod SUPPorted')
    hwdgm.write(':SWITch:SCAN')
    detected_switches = hwdgm.query(':CONFigure:SWITch:ALL?')
    hwdgm.timeout = timeout
    for switch in switches:
        if switch in detected_switches:
            hwdgm.write(':CONFigure:SWITch:ACTive ' + switch + ',ON')
        else:
            raise NoSwitchException('A switch module was not found!')
    return


def place_dcams_on_switch_diagram(hwdgm, required_dcams):
    """ Confirms two N1092As found and places the N1092As on the Switch Diagram but does not connect ports. """
    found = hwdgm.query(':CONFigure:MODule:ALL?')
    dcams_found = found.split(',')
    found = list()
    for scope in required_dcams:
        for scope_name in dcams_found:
            if scope in scope_name:
                hwdgm.write(':CONFigure:MODule:ACTive ' + scope_name + ',ON')
                print(scope_name + ' placed on Switch Diagram.')
                found.append(scope_name)
                dcams_found.remove(scope_name)
                break
    if len(found) != len(required_dcams):
        raise NoModuleException('Required module was not found!')
    return found


def connect_dcams_to_switch(hwdgm, dcam_scope_names, switches):
    """ Connects switch Ports to Channel A on two N1092A. For example,
    ':CONFigure:PORT:CONNect "N7734A","A","N1092A-US92000001","A"'  """
    hwdgm.write(':CONFigure:PORT:CONNect ' + switches[0] + ',"A",' + dcam_scope_names[0] + ',"A"')


def place_fixtures_on_switch_diagram(hwdgm, dut_fixtures, lane_count):
    """ Places DUT Fixture 1 and DUT Fixture 2 on the Switch Diagram but does not connect ports. """
    hwdgm.write(':CONFigure:NLANes ' + str(lane_count))
    fixture_list = list(dut_fixtures.items())
    for station, fixture_name in fixture_list:
        hwdgm.write(':CONFigure:FIXTure:ACTive ' + fixture_name + ', ON')
        hwdgm.write(':CONFigure:FIXTure:TYPE ' + fixture_name + ', NORMal')
        print('Fixture ' + fixture_name + ' placed on Switch Diagram.')
    return


def connect_fixtures_to_switches(hwdgm, dut_fixtures, switches):
    """ Connects fixtures to switch ports. For example,
    ':CONFigure:PORT:CONNect "Test Station 1", "1", "N7731A (Switch 1)", "A"'
    """
    hwdgm.write(':CONFigure:PORT:CONNect ' + dut_fixtures['1'] + ', "1", ' + switches[0] + ', "1"')
    hwdgm.write(':CONFigure:PORT:CONNect ' + dut_fixtures['1'] + ', "2", ' + switches[0] + ', "2"')
    hwdgm.write(':CONFigure:PORT:CONNect ' + dut_fixtures['1'] + ', "3", ' + switches[0] + ', "3"')
    hwdgm.write(':CONFigure:PORT:CONNect ' + dut_fixtures['1'] + ', "4", ' + switches[0] + ', "4"')
    hwdgm.write(':CONFigure:PORT:CONNect ' + dut_fixtures['2'] + ', "1", ' + switches[0] + ', "5"')
    hwdgm.write(':CONFigure:PORT:CONNect ' + dut_fixtures['2'] + ', "2", ' + switches[0] + ', "6"')
    hwdgm.write(':CONFigure:PORT:CONNect ' + dut_fixtures['2'] + ', "3", ' + switches[0] + ', "7"')
    hwdgm.write(':CONFigure:PORT:CONNect ' + dut_fixtures['2'] + ', "4", ' + switches[0] + ', "8"')


def switch_diagram_ok(hwdgm):
    """ Switch diagram must be correct before Sessions can be started. """
    if 'CORR' in hwdgm.query(':CONFigure:STATus?'):
        hwdgm.write('*CLS')
        print('The switch diagram is correct!')
        return True
    else:
        print(hwdgm.query(':CONFigure:STATus:REASon?'))
        return False


def launch_stations(hwdgm, assignments, number_of_sessions):
    """ Configures two stations, assigns DUT1 to Station 1, DUT2 to Station 2, and launches the
    station child process. One fixture per Session (Test Station) """
    hwdgm.timeout = 120000
    hwdgm.write(':CONFigure:AASessions OFF')  # Auto Session assignment off
    hwdgm.write(':CONFigure:NSTations ' + str(number_of_sessions))
    for i in range(1, number_of_sessions + 1):
        fixture_name = assignments[str(i)]
        hwdgm.write(':CONFigure:FIXTure:STATion ' + fixture_name + ', ' + str(i))


    print('Starting Sessions. This takes about a minute.', flush=True)
    hwdgm.write(':STARt')
    hwdgm.query('*OPC?')
    print('FlexOTO Sessions are ready.', flush=True)
    hwdgm.timeout = 20000

#  Main Loop
s = '\nDemo of bootup script with:\n\tKeysight N7734A, \
\n\t2 four-lane fixtures,\n\t1 N1092A, and\n\t2 Sessions (Test Stations).'
print(s)
hwdiagram = open_connection(visa_address)
place_switches_on_switch_diagram(hwdiagram, SWITCHES)
scope_names = place_dcams_on_switch_diagram(hwdiagram, DCAM_MODELS)
connect_dcams_to_switch(hwdiagram, scope_names, SWITCHES)
place_fixtures_on_switch_diagram(hwdiagram, FIXTURES, LANE_CNT)
connect_fixtures_to_switches(hwdiagram, FIXTURES, SWITCHES)
print('All port connections on Switch Diagram made.')
if switch_diagram_ok(hwdiagram):
    launch_stations(hwdiagram, FIXTURES, STATION_CNT)
    print('\nRun the "test-station.py" script to run Test Programs.')
else:
    print('\nProgram aborted. The Hardware Diagram is not properly configured.')
hwdiagram.write(':SYSTem:GTLocal')
hwdiagram.close()