def printError(curr_phase,msg):
    """
    Prints an error message using the formatting from util.py
    :param curr_phase: Current phase of system.
    :param msg: Message
    """
    util.printf(curr_phase, "Error", msg)
def printMsg(curr_phase,msg):
    """
    Prints a message using the formatting from util.py
    :param curr_phase: Current phase of system.
    :param msg: Message
    """
    util.printf(curr_phase, None, msg)
def run_experiments(cmds, meas, calib, plot):
    """
    Runs all experiments specified in cmds and uses the meas, calib, and plot settings to configure measurement,
    calibration, and plotting.
    :param cmds: List containing the sub-experiments to run.
    :param meas: Dictionary containing the measurement configuration.
    :param calib: Dictionary containing the calibration configuration.
    :param plot: Dictionary containing the plotting configuration.
    :return: Returns a True tuple
    """
    for sub_expt in cmds:
        # Split cmds into usable pieces
        expt_type = sub_expt['experiment type']

        # Run the appropriate function for the sub-experiment
        if expt_type == "sweepFreq":
            util.printf(curr_phase, "Debug", f"Running Type: {expt_type}")
            # print(sub_expt)
            error_code = expt.run_sweepFreq(sub_expt, meas, calib, plot)
        elif expt_type == "sweepPhi":
            util.printf(curr_phase, "Debug", f"Running Type: {expt_type}")
            error_code = expt.run_sweepPhi(sub_expt)
        elif expt_type == "sweepTheta":
            util.printf(curr_phase, "Debug", f"Running Type: {expt_type}")
            error_code = expt.run_sweepTheta(sub_expt)
        else:
            util.printf(curr_phase, "Error",
                        f"Could not run experiment of type '{expt_type}'")
            return False, expt_type
        handle_error_code(error_code)

    return True, True, True

    single_cfg = {
        'test_phi': args.test_phi,
        'zero_test_phi': args.zero_test_phi,
        'align_test_phi': args.align_test_phi,
        'test_theta': args.test_theta,
        'zero_test_theta': args.zero_test_theta,
        'align_test_theta': args.align_test_theta,
        'probe_phi': args.probe_phi,
        'zero_probe_phi': args.zero_probe_phi,
        'align_probe_phi': args.align_probe_phi
    }
def plot_data_file(data_file, plot_type, sParams, plot_freq, plot_t_phi,
                   plot_t_theta, plot_p_phi):

    if data_file != '':
        # Find data file
        if data_file.rfind(".") == -1:
            data_file += ".csv"
        elif not data_file.endswith(".csv"):
            util.printf(
                curr_phase, "Error",
                f"The '{data_file}' is not a CSV file. Ensure that '{data_file}'"
                f" is a CSV file.")
            return False

        csv_file_name = util.get_file_path(data_file, "data")
        # print(csv_file_name)
        if not os.path.isfile(csv_file_name) or not csv_file_name:
            path = util.get_file_path('', "data")
            util.printf(
                curr_phase, "Error",
                f"Could not locate the file '{data_file}'. Ensure that '{data_file}'"
                f" is located in the data file repository:\n\t\t'{path}'.")
            return False

        plot_file_name = csv_file_name[0:len(csv_file_name) - 4] + ".pdf"
        util.printf(curr_phase, None,
                    f"Plotting '{data_file}' to {plot_file_name}")
        if plot_type == "3d":
            try:
                plots.plot3DRadPattern(csv_file_name, plot_file_name, sParams,
                                       plot_freq)
            except:
                return False
        elif plot_type == "cutPhi":
            try:
                plots.plotPhiCut(csv_file_name, plot_file_name, sParams,
                                 plot_freq, plot_t_phi)
            except:
                return False
        elif plot_type == "cutTheta":
            try:
                plots.plotThetaCut(csv_file_name, plot_file_name, sParams,
                                   plot_freq, plot_t_theta)
            except:
                return False
        else:
            return False
        return True
    return False
 def printf(msg):
     util.printf(current_phase, None, msg)
def rotateMotorAbs(angle, motor, direction, grad_accel):
    """
    Rotates the selected motor to an absolute angle.
    :param angle The angle to which to rotate the motor.
    :param motor Which motor to rotate -- see below for valid values.
    :param direction Which direction in which to rotate the motor -- see below for valid values.
    :param grad_accel Whether or not to accelerate motor gradually (true for yes).
    :return Error code indicating whether or not it was successful.
    """
    printf('Setup', None, 'Parsing arguments...')
    # Parse arguments and verify that they are valid.
    try:
        assert motor in ['test phi', 'test theta', 'probe phi']
        assert direction in [None, 'cw', 'ccw']
        assert grad_accel in [None, True, False]
        if grad_accel == None:
            grad_accel = motor == 'test theta'
        assert type(angle) == float
        printf('Setup', None, '\tDone.')
        printf('Setup', None, '\tMotor: ' + motor)
        if direction != None:
            printf('Setup', None, '\tDirection: ' + direction)
        else:
            printf('Setup', None, '\tDirection: computing optimal direction.')
        printf('Setup', None, '\tGradual acceleration: ' + str(grad_accel))
        printf('Setup', None, 'Detecting motor drivers...')
        MD = initMotorDriver(motor)
    except:
        return error_codes.BAD_ARGS
    # Determine whether or not the desired USB device was attached to the computer.
    if MD == error_codes.CONNECTION_PROBE or MD == error_codes.CONNECTION_TEST:
        return MD
    printf('Setup', None, '\tDone.')
    printf('Setup', None, 'Calculating steps to rotate...')
    # Calculate the angle by which we need to rotate.
    angle = np.mod(angle + 180, 360) - 180
    try:
        current_angle = getCurrentAngle(MD, motor)
    except:
        return error_codes.CALIBRATION
    num_steps = angleToSteps(angle - current_angle, motor)
    if direction == None:
        if np.abs(num_steps + (SPR[motor] if num_steps < 0 else 0)) < np.abs(
                num_steps - (SPR[motor] if num_steps > 0 else 0)):
            direction = 'cw'
        else:
            direction = 'ccw'
    if direction == 'cw' and num_steps < 0:
        num_steps += SPR[motor]
    elif direction == 'ccw' and num_steps > 0:
        num_steps -= SPR[motor]
    printf('Setup', None, '\tDone.')
    printf(
        'Setup', None,
        '\tRotating to %f degrees through %d-step %s offset from current orientation.'
        % (angle, np.abs(num_steps), direction))
    printf('Running', None, 'Starting motor rotation...')
    t0 = time.time()
    # Rotate the motor.
    try:
        error_code = MD.turnMotor('theta' if motor == 'test theta' else 'phi',
                                  int(np.abs(num_steps)), direction,
                                  grad_accel)
        printf('Running', None, '\tDone.')
        printf('Running', None,
               '\tTime taken: %f seconds.' % (time.time() - t0))
        del MD
        return error_code
    except:
        del MD
        return error_codes.MISC
def alignMotor(motor, direction):
    """
    Rotates the selected motor to its end switch.
    :param motor Which motor to rotate -- see below for valid values.
    :param direction Which direction to initially look for the end switch in -- see below for valid values.
    :return Error code indicating whether or not it was successful.
    """
    printf('Setup', None, 'Parsing arguments...')
    # Parse arguments and verify that they are valid.
    try:
        assert motor in ['test phi', 'test theta', 'probe phi']
        assert direction in [None, 'cw', 'ccw']
        if direction == None:
            direction = 'cw'
        printf('Setup', None, '\tDone.')
        printf('Setup', None, '\tMotor: ' + motor)
        printf('Setup', None, '\tDirection: ' + direction)
        printf('Setup', None, 'Detecting motor drivers...')
        MD = initMotorDriver(motor)
    except:
        return error_codes.BAD_ARGS
    # Determine whether or not we found the desired USB device attached to the computer.
    if MD == error_codes.CONNECTION_PROBE or MD == error_codes.CONNECTION_TEST:
        return MD
    printf('Setup', None, '\tDone.')
    printf('Running', None, 'Rotating to end switch...')
    t0 = time.time()
    # Rotate the motor to the end switch.
    try:
        error_code = MD.findEndSwitch(
            'theta' if motor == 'test theta' else 'phi', direction)
        del MD
        printf('Running', None, '\tDone.')
        printf('Running', None,
               '\tTime taken: %f seconds.' % (time.time() - t0))
        return error_code
    except:
        del MD
        return error_codes.MISC
def zeroCurrentAngle(motor):
    """
    Programs the current angle to 0 in flash memory for the selected device.
    :param motor Which motor to configure -- see below for valid values.
    :return Error code indicating whether or not it was successful.
    """
    printf('Setup', None, 'Parsing arguments...')
    # Parse arguments and verify that they are valid.
    try:
        assert motor in ['test phi', 'test theta', 'probe phi']
        printf('Setup', None, '\tDone.')
        printf('Setup', None, '\tMotor: ' + motor)
        printf('Setup', None, 'Detecting motor drivers...')
        MD = initMotorDriver(motor)
    except:
        return error_codes.BAD_ARGS
    # Determine whether or not we found the desired USB device attached to the computer.
    if MD == error_codes.CONNECTION_PROBE or MD == error_codes.CONNECTION_TEST:
        return MD
    printf('Setup', None, '\tDone.')
    printf('Running', None, 'Reading current angle...')
    # Read the current angle of the device.
    try:
        current_angle = MD.getOrientation(
            'theta' if motor == 'test theta' else 'phi', 'current')
    except:
        return error_codes.CALIBRATION
    printf('Running', None, '\tDone.')
    printf('Running', None, 'Updating 0 angle...')
    # Program the current angle to be the aligned angle (0).
    try:
        if motor == 'test theta':
            MD.setAlignedOrientation(theta=current_angle)
        else:
            MD.setAlignedOrientation(phi=current_angle)
        del MD
        printf('Running', None, '\tDone.')
        return error_codes.SUCCESS
    except:
        del MD
        return error_codes.MISC
def rotateMotorInc(angle, motor, direction, grad_accel):
    """
    Rotate the given motor to the selected angle relative to the current angle.
    :param angle The angle by which to rotate the motor.
    :motor Which motor to rotate -- see below for valid values.
    :direction Which direction in which to rotate the motor -- see below for valid values.
    :param grad_accel Whether or not to accelerate the motor gradually (True for yes).
    :return Error code indicating whether it was successful or not.
    """
    printf('Setup', None, 'Parsing arguments...')
    # Parse arguments and verify that they are valid.
    try:
        assert motor in ['test phi', 'test theta', 'probe phi']
        assert direction in [None, 'cw', 'ccw']
        if direction == None:
            direction = 'cw'
        assert grad_accel in [None, True, False]
        if grad_accel == None:
            grad_accel = motor == 'test theta'
        assert type(angle) == float
        printf('Setup', None, '\tDone.')
        printf('Setup', None, '\tMotor: ' + motor)
        printf('Setup', None, '\tDirection: ' + direction)
        printf('Setup', None, '\tGradual acceleration: ' + str(grad_accel))
        printf('Setup', None, 'Detecting motor drivers...')
        MD = initMotorDriver(motor)
    except:
        return error_codes.BAD_ARGS
    # Determine whether or not we found the desired USB device attached to the computer.
    if MD == error_codes.CONNECTION_PROBE or MD == error_codes.CONNECTION_TEST:
        return MD
    printf('Setup', None, '\tDone.')
    printf('Setup', None, 'Calculating steps to rotate...')
    # Calculate the number of steps by which to rotate.
    num_steps = angleToSteps(angle, motor)
    if num_steps < 0:
        num_steps = np.abs(num_steps)
        direction = 'cw' if direction == 'ccw' else 'ccw'
    printf('Setup', None, '\tDone.')
    printf(
        'Setup', None,
        '\tRotating by %f-degree increment through %d-step %s offset from current orientation.'
        % (np.abs(angle), np.abs(num_steps), direction))
    printf('Running', None, 'Starting motor rotation...')
    t0 = time.time()
    # Rotate the motor.
    try:
        error_code = MD.turnMotor('theta' if motor == 'test theta' else 'phi',
                                  num_steps, direction, grad_accel)
        del MD
        printf('Running', None, '\tDone.')
        printf('Running', None,
               '\tTime taken: %f seconds.' % (time.time() - t0))
        return error_code
    except:
        del MD
        return error_codes.MISC
def handle_error_code(error_code):
    """
    Identifies error codes and prints the appropriate error message associated with a code. If the error could not be
    identified, then the an assertion error will be raised.
    :param error_code: Error code that corresponds to an error.
    """
    curr_phase = "Shutdown"
    if error_code == error_codes.SUCCESS:  # routine finished without issues
        util.printf(curr_phase, None,
                    "Successfully ran routine without issues. ")
    elif error_code == error_codes.CONNECTION:  # could not find any connected motor driver PCBs
        util.printf(
            curr_phase, "Error",
            "No USB devices connected. Ensure the test-side and probe-side devices"
            " are connected and powered on. ")
    elif error_code == error_codes.CONNECTION_PROBE:  # could not find a probe motor driver PCB
        util.printf(
            curr_phase, "Error", "No probe-side USB devices connected."
            " Ensure the probe-side device is connected and powered on. ")
    elif error_code == error_codes.CONNECTION_TEST:  # could not find a test motor driver PCB
        util.printf(
            curr_phase, "Error", "No test-side USB devices connected."
            " Ensure the test-side device is connected and powered on. ")
    elif error_code == error_codes.DISTINCT_IDS:  # detected two motor driver PCBs, but they were both configured as test or probe
        util.printf(
            curr_phase, "Error",
            "USB devices must be of different types. Ensure that the test-side device is"
            " set to TX and that the probe-side device is set to RX.")
    elif error_code == error_codes.VNA:  # could not connect to VNA
        util.printf(
            curr_phase, "Error",
            "No GPIB devices connected. Ensure the VNA is connected and powered on. "
        )
    elif error_code == error_codes.TEST_THETA_FAULT:  # test-theta motor fault
        util.printf(
            curr_phase, "Error",
            "Motor driver fault detected on the test-side theta motor. Ensure"
            " that the theta motor driver is properly connected to the test-side device."
        )
    elif error_code == error_codes.TEST_PHI_FAULT:  # test-phi motor fault
        util.printf(
            curr_phase, "Error",
            "Motor driver fault detected on the test-side phi motor. Ensure"
            " that the phi motor driver is properly connected to the test-side device."
        )
    elif error_code == error_codes.PROBE_PHI_FAULT:  # probe-phi motor fault
        util.printf(
            curr_phase, "Error",
            "Motor driver fault detected on the probe-side phi motor. Ensure"
            " that the phi motor driver is properly connected to the probe-side device."
        )
    elif error_code == error_codes.ALIGNMENT:  # alignment routine failed
        util.printf(
            curr_phase, "Error",
            "Alignment error detected. System could not be aligned. Try running the"
            " calibration routine to ensure proper alignment. ")
    elif error_code == error_codes.BAD_ARGS:  # routine was called with invalid arguments
        util.printf(
            curr_phase, "Error",
            "Unable to run routine as invalid arguments were entered.")
    elif error_code == error_codes.MISC:  # issue not listed above
        util.printf(curr_phase, "Error", "An unknown error has occurred.")
    elif error_code == error_codes.STOPPED:
        util.printf(
            curr_phase, "Error",
            "The user issued a keyboard interrupt to prematurely stop the program."
        )
    elif error_code == error_codes.CALIBRATION:
        util.printf(
            curr_phase, "Error",
            "The selected device is not calibrated and must be calibrated to perform the requested action."
            " This means that the device has never been calibrated, or since the last calibration it has encountered an error during a rotation command."
            " The user is advised to rotate to the end switch for this device, then manually rotate to the zero"
            " angle and specify it as such.")
    else:
        assert False
def process_config(config_name):
    """
    Parses the configuration file and generates the appropriate commands for plotting, measurement setup,
    experiments, and calibration.
    :param config_name: Name of the configuration file to parse.
    """
    if config_name != '' and config_name is not None:
        # Find Config
        util.printf(
            curr_phase, None,
            f"Starting configuration file parsing process on {config_name}...")
        full_cfg_name = parser.find_config(config_name)
        if not full_cfg_name:
            util.printf(
                curr_phase, "Error",
                f"Could not locate the file '{config_name}'. Ensure that '{config_name}'"
                f" is located in the configuration file repository:\n\t\t "
                f"'{util.get_root_path() + parser.config_base}'.")
            return False
        # Get flow and meas config from the configuration file
        flow, meas, calib, plot = parser.get_config(full_cfg_name)
        errors = 0
        if not flow:
            util.printf(
                curr_phase, "Error",
                f"Could not read in data from '{config_name}'. Ensure that the 'flow' section"
                f" in '{config_name}' is correctly formatted. See the User Manual for details."
            )
            errors += 1
        if not meas:
            util.printf(
                curr_phase, "Error",
                f"Could not read in data from '{config_name}'. Ensure that the 'meas' section"
                f" in '{config_name}' is correctly formatted. See the User Manual for details."
            )
            errors += 1
        if not calib:
            util.printf(
                curr_phase, "Error",
                f"Could not read in data from '{config_name}'. Ensure that the 'calibrate' "
                f"section in '{config_name}' is correctly formatted. "
                f"See the User Manual for details.")
            errors += 1
        if not plot:
            util.printf(
                curr_phase, "Error",
                f"Could not read in data from '{config_name}'. Ensure that the 'plot' section"
                f" in '{config_name}' is correctly formatted. See the User Manual for details."
            )
            errors += 1
        if errors != 0:
            return False

        # Generate commands
        cmds = parser.gen_expt_cmds(flow)
        if not cmds:
            util.printf(
                curr_phase, "Error",
                f"Could not generate experiment commands from '{config_name}'."
            )
            return False
        util.printf(
            curr_phase, None,
            f"Successfully generated experiment commands from '{config_name}'."
        )
        return {"cmds": cmds, "meas": meas, "calib": calib, "plot": plot}
    else:
        util.printf(
            curr_phase, "Error",
            f"No configuration file was passed in, could not generate experiment commands."
        )
        return False
def process_cmd_line():
    """
    Processes the command line arguments and sets up the
    system control variables accordingly. If an error occurred, an error message indicating the fault will be printed before the returning False.
    :return Returns options if no errors occurred, otherwise False.
    """
    # Set up parser
    opt_parser = OptionParser()
    opt_parser.prog = "direcMeasure"
    usage = set_usage(opt_parser.prog)
    opt_parser.set_usage(usage)
    opt_parser.set_defaults(run_type="f", verbose=False)

    # Main options
    opt_parser.add_option(
        "-c",
        "--config",
        type="string",
        action="store",
        dest="cfg",
        default='',
        help=
        "Configuration file used to control the system. Must be a JSON file.")
    opt_parser.add_option("-a",
                          "--alignOnly",
                          action="callback",
                          callback=config_run,
                          dest="run_type",
                          help="Only run the alignment routine.")
    opt_parser.add_option("--calibrate",
                          action="store_true",
                          dest="calibrate",
                          default=False,
                          help="Run the calibration interface.")
    opt_parser.add_option("--plot",
                          action="store_true",
                          dest="plot",
                          default=False,
                          help="Run the calibration interface.")
    # Plot options
    opt_parser.add_option("--dataFile",
                          type="string",
                          action="store",
                          dest="data_file",
                          default='',
                          help="Plot option. Input data file to plot")
    opt_parser.add_option(
        "--plotType",
        type="string",
        action="store",
        dest="plot_type",
        default='',
        help=
        f"Plot option. Type of plot to generate. Must be one of the following"
        f" {parser.ALLOWED_PLOT_TYPES}.")
    opt_parser.add_option(
        "--freq",
        type="string",
        action="store",
        dest="plot_freq",
        default='',
        help="Plot option. Frequency to plot at. Must be in Hz, MHz, or GHz")
    opt_parser.add_option(
        "--phi",
        type="float",
        action="store",
        dest="plot_phi",
        default=200.0,
        help="Plot option. Test phi angle to plot at. Must be in degrees "
        "and between -180 and 180 degrees.")
    opt_parser.add_option(
        "--theta",
        type="float",
        action="store",
        dest="plot_theta",
        default=200.0,
        help="Plot option. Test theta angle to plot at. Must be in degrees "
        "and between -180 and 180 degrees.")
    opt_parser.add_option(
        "--probePhi",
        type="float",
        action="store",
        dest="plot_p_phi",
        default=200.0,
        help="Plot option. Probe phi angle to plot at. Must be in degrees "
        "and between -180 and 180 degrees.")
    opt_parser.add_option("--sParams",
                          type="string",
                          action="store",
                          dest="sParams",
                          default="S21",
                          help="Plot option. S parameters to plot.")
    opt_parser.add_option("--logName",
                          type="string",
                          action="store",
                          dest="log_name",
                          default=None,
                          help="Filename for terminal output log.")
    opt_parser.add_option("--logPath",
                          type="string",
                          action="store",
                          dest="log_path",
                          default=None,
                          help="Filepath for terminal output log.")
    opt_parser.add_option(
        "--dataPath",
        type="string",
        action="store",
        dest="data_path",
        default=None,
        help="Filepath for data file taken during experiment.")
    opt_parser.add_option(
        "--dataName",
        type="string",
        action="store",
        dest="data_name",
        default=None,
        help="Filename for data file taken during experiment.")
    opt_parser.add_option(
        "--plotName",
        type="string",
        action="store",
        dest="plot_name",
        default=None,
        help="Filename for plot generated during experiment.")
    opt_parser.add_option(
        "--plotPath",
        type="string",
        action="store",
        dest="plot_path",
        default=None,
        help="Filepath for plot generated during experiment.")

    opt_parser.add_option(
        "--setTestPhi",
        type="float",
        action="store",
        dest="test_phi",
        default=None,
        help=
        "Sets the test-side phi angle to the specified angle. Must be in degrees "
        "and between -180 and 180 degrees.")
    opt_parser.add_option(
        "--zeroTestPhi",
        action="store_true",
        dest="zero_test_phi",
        default=False,
        help="Sets the current test-side phi angle to be the zero reference.")
    opt_parser.add_option(
        "--alignTestPhi",
        action="store_true",
        dest="align_test_phi",
        default=False,
        help="Aligns the test-side phi motor with the end-switch.")

    # Test Theta Options
    opt_parser.add_option(
        "--setTestTheta",
        type="float",
        action="store",
        dest="test_theta",
        default=None,
        help=
        "Sets the test-side theta angle to the specified angle. Must be in degrees "
        "and between -180 and 180 degrees.")
    opt_parser.add_option(
        "--zeroTestTheta",
        action="store_true",
        dest="zero_test_theta",
        default=False,
        help="Sets the current test-side theta angle to be the zero reference."
    )
    opt_parser.add_option(
        "--alignTestTheta",
        action="store_true",
        dest="align_test_theta",
        default=False,
        help="Aligns the test-side test motor with the end-switch.")

    # Probe Theta Options
    opt_parser.add_option(
        "--setProbePhi",
        type="float",
        action="store",
        dest="probe_phi",
        default=None,
        help=
        "Sets the probe-side phi angle to the specified angle. Must be in degrees "
        "and between -180 and 180 degrees.")
    opt_parser.add_option(
        "--zeroProbePhi",
        action="store_true",
        dest="zero_probe_phi",
        default=False,
        help="Sets the current probe-side phi angle to be the zero reference.")
    opt_parser.add_option(
        "--alignProbePhi",
        action="store_true",
        dest="align_probe_phi",
        default=False,
        help="Aligns the probe-side phi motor with the end-switch.")

    # Options determining how the motor will rotate
    opt_parser.add_option("--direction",
                          action="store",
                          dest="direction",
                          default=None,
                          help="The direction in which motor should rotate.")
    opt_parser.add_option(
        "--gradualAcceleration",
        action="store_true",
        dest="grad_accel",
        default=None,
        help=
        "Gradually accelerate the motor to its maximum frequency. Recommended for test-theta motor."
    )
    opt_parser.add_option(
        "--jumpAcceleration",
        action="store_false",
        dest="grad_accel",
        help=
        "Instantly accelerate the motor to its maximum frequency. Recommended for test-phi and probe-phi motors."
    )
    opt_parser.add_option(
        "--incremental",
        action="store_true",
        dest="incremental",
        default=False,
        help=
        "Whether input angle should be interpreted as absolute or relative to current angle."
    )

    # Check to make sure a config file was entered with the -c
    index = -1
    for i in range(len(sys.argv)):
        if sys.argv[i] == "-c" or sys.argv[i] == "--config":
            index = i + 1

    if index >= len(sys.argv) or index > 0 and opt_parser.has_option(
            sys.argv[index]):
        sys.argv.insert(index, None)

    # Parse command line
    (options, args) = opt_parser.parse_args()
    # print(options)

    # Check for single mode
    if options.test_phi != None or options.zero_test_phi or options.align_test_phi or \
            options.test_theta != None or options.zero_test_theta or options.align_test_theta \
            or options.probe_phi != None or options.zero_probe_phi or options.align_probe_phi:
        if options.run_type == 'f':
            options.run_type = 's'
        else:
            options.run_type = 'e'

    # Error Checking
    if options.run_type == "e":
        util.printf(
            curr_phase, "Error",
            "Cannot simultaneously run the alignment routine only and run the system with out "
            "the alignment routine. See usage for more information on command line options."
        )
        opt_parser.print_help()
        return False

    # Config file checks
    if options.cfg is None:
        util.printf(
            curr_phase, "Error",
            f"Configuration file flag detected but no configuration was detected. See usage "
            f"for more information on command line options. ")
        opt_parser.print_help()
        return False

    num_modes = int(options.cfg != '') + int(options.run_type == 'a') + int(options.run_type == 's') + \
                int(options.calibrate) + int(options.plot)

    if num_modes == 0:
        util.printf(
            curr_phase, "Error",
            "Cannot configure system as no command lines arguments were inputted."
            " See usage for more information on command line options. ")
        opt_parser.print_help()
        return False
    if num_modes > 1:
        util.printf(
            curr_phase, "Error",
            "Mutually-exclusive options specified. Cannot simultaneously run the "
            "calibration routine and the run the full run the system. See usage for more "
            "information on command line options.")
        opt_parser.print_help()
        return False
    if options.calibrate:
        options.run_type = "c"

    if options.plot:
        options.run_type = "p"
        if options.data_file == '':
            util.printf(
                curr_phase, "Error",
                f"Plotting requested but no input data file was entered."
                f" See usage for more information on command line options.")
            opt_parser.print_help()
            return False

        if options.data_file == '' or not options.data_file.endswith(".csv"):
            util.printf(
                curr_phase, "Error",
                f"The input data file entered '{options.data_file}' is not a csv file. "
                f" See usage for more information on command line options.")
            opt_parser.print_help()
            return False

        if options.plot_type == '':
            util.printf(
                curr_phase, "Error",
                f"Plotting requested but no plot type was specified. "
                f" See usage for more information on command line options.")
            opt_parser.print_help()
            return False

        if options.plot_type not in parser.ALLOWED_PLOT_TYPES:
            util.printf(
                curr_phase, "Error",
                f"Plotting requested but invalid plot type {options.plot_type} was specified. "
                f"Plot type must one of the following {parser.ALLOWED_PLOT_TYPES}"
                f" See usage for more information on command line options.")
            opt_parser.print_help()
            return False

        if options.plot_type == "cutPhi" and options.plot_phi == 200:
            util.printf(
                curr_phase, "Error",
                f"Phi cut plot requested but no phi angle was specified. "
                f" See usage for more information on command line options.")
            opt_parser.print_help()
            return False
        elif options.plot_type == "cutTheta" and options.plot_theta == 200:
            util.printf(
                curr_phase, "Error",
                f"Theta cut plot requested but no theta angle was specified. "
                f" See usage for more information on command line options.")
            opt_parser.print_help()
            return False

        if 'MHz' in options.plot_freq:
            options.plot_freq = 1e6 * float(options.plot_freq[:-3])
        elif 'GHz' in options.plot_freq:
            options.plot_freq = 1e9 * float(options.plot_freq[:-3])
        elif 'Hz' in options.plot_freq:
            options.plot_freq = float(options.plot_freq[:-3])
        else:
            util.printf(
                curr_phase, "Error",
                f"Plotting requested but invalid plot frequency {options.plot_freq} was specified. "
                f"Plot type must be in units of Hz, MHz, or GHz (e.g. 10GHz or \"10 GHz\")."
                f" See usage for more information on command line options.")
            opt_parser.print_help()
            return False

    if options.cfg != '' and not options.cfg.endswith(".json"):
        util.printf(
            curr_phase, "Error",
            f"The configuration file entered '{options.cfg}' is not a JSON file. "
            f" See the User Manual for more information on configuration files and "
            f"usage for more information on command line options.")
        opt_parser.print_help()
        return False

    return options
        'direction': args.direction,
        'incremental': args.incremental,
        'grad_accel': args.grad_accel
    }

    run_type = args.run_type
    if run_type != "c":
        util.initLog(args.log_name, args.log_path)
    if run_type == "p":
        curr_phase = 'Plotting'
        res = plot_data_file(args.data_file, args.plot_type, args.sParams,
                             args.plot_freq, args.plot_phi, args.plot_theta,
                             args.plot_p_phi)
        if not res:
            util.printf(
                curr_phase, "Error",
                f"Could not generate '{args.plot_type}' plot from '{args.data_file}'."
            )
        exit(1)

    if run_type == "a":
        util.printf(curr_phase, None, "Running the alignment routine only.")

    elif run_type == "c":
        util.printf(curr_phase, "Debug", "Starting the calibration interface.")

    # Process Configuration File if running the entire system
    sys_cmds = False
    if run_type in ("f"):  # , "s"):
        sys_cmds = process_config(cfg)
        if not sys_cmds:
            exit(-1)