Exemplo n.º 1
0
def get_input_value():
    """
    Get the voltage from the user and validate it.
    """

    # Get the min and max voltage values for the analog outputs to validate
    # the user input.
    min_v = mcc152.info().AO_MIN_RANGE
    max_v = mcc152.info().AO_MAX_RANGE

    while True:
        message = ("Enter a voltage between {0:.1f} and {1:.1f}, "
                   "non-numeric character to exit: ".format(min_v, max_v))

        if version_info.major > 2:
            str_v = input(message)
        else:
            str_v = raw_input(message)

        try:
            value = float(str_v)
        except ValueError:
            raise
        else:
            if (value < min_v) or (value > max_v):
                # Out of range, ask again.
                print("Value out of range.")
            else:
                # Valid value.
                return value
def get_input():
    """
    Get a value from the user.
    """
    max_value = (1 << mcc152.info().NUM_DIO_CHANNELS)

    while True:
        # Wait for the user to enter a response
        message = "Enter the output value, non-numeric character to exit: "
        if sys.version_info.major > 2:
            response = input(message)
        else:
            response = raw_input(message)

        # Try to convert it to a number with automatic base conversion
        try:
            value = int(response, 0)
        except ValueError:
            return None
        else:
            # Compare the number to min and max allowed.
            if (value < 0) or (value >= max_value):
                # Out of range, ask again.
                print("Value out of range.")
            else:
                # Valid value.
                return value
def get_channel():
    """
    Get a channel number from the user.
    """
    num_channels = mcc152.info().NUM_DIO_CHANNELS

    while True:
        # Wait for the user to enter a response
        message = "Enter a channel between 0 and {},".format(num_channels - 1)
        message += " non-numeric character to exit: "
        if sys.version_info.major > 2:
            response = input(message)
        else:
            response = raw_input(message)

        # Try to convert it to a number.
        try:
            value = int(response)
        except ValueError:
            return None
        else:
            # Compare the number to min and max allowed.
            if (value < 0) or (value >= num_channels):
                # Out of range, ask again.
                print("Value out of range.")
            else:
                # Valid value.
                return value
def main():
    """
    This function is executed automatically when the module is run directly.
    """

    print("MCC 152 digital output write example.")
    print("Sets all digital I/O channels to output then gets channel and")
    print("value input from the user and updates the output.")
    print("   Methods demonstrated:")
    print("      mcc152.dio_reset")
    print("      mcc152.dio_output_write_bit")
    print("      mcc152.dio_config_write_bit")
    print("      mcc152.info")
    print()

    # Get an instance of the selected hat device object.
    address = select_hat_device(HatIDs.MCC_152)

    print("\nUsing address {}.\n".format(address))

    hat = mcc152(address)

    # Reset the DIO to defaults (all channels input, pull-up resistors
    # enabled).
    hat.dio_reset()

    # Set all channels as outputs.
    for channel in range(mcc152.info().NUM_DIO_CHANNELS):
        try:
            hat.dio_config_write_bit(channel, DIOConfigItem.DIRECTION, 0)
        except (HatError, ValueError):
            print("Could not configure the channel as output.")
            sys.exit()

    run_loop = True
    error = False
    # Loop until the user terminates or we get a library error.
    while run_loop and not error:
        channel, value = get_input()

        if channel is None:
            run_loop = False
        else:
            try:
                hat.dio_output_write_bit(channel, value)
            except (HatError, ValueError):
                error = True

        if error:
            print("Error writing the output.")

    # Return the DIO to default settings
    if not error:
        hat.dio_reset()
Exemplo n.º 5
0
    def updateControlsFromDevice(self):
        # Read the current DIO state
        dir_tuple = self.board.dio_config_read_tuple(DIOConfigItem.DIRECTION)
        out_tuple = self.board.dio_output_read_tuple()

        for index in range(mcc152.info().NUM_DIO_CHANNELS):
            if dir_tuple[index] == 0:
                self.dirs[index].config(text='Output', relief=SUNKEN)
            else:
                self.dirs[index].config(text='Input', relief=RAISED)

            if out_tuple[index] == 0:
                self.out_states[index].config(text='0', relief=SUNKEN)
            else:
                self.out_states[index].config(text='1', relief=RAISED)

        # Analog output state is unknown so set it to 0.0
        for channel in range(mcc152.info().NUM_AO_CHANNELS):
            self.board.a_out_write(channel, 0.0)
            self.aout_sliders[channel].set(0.0)
Exemplo n.º 6
0
    def updateInputs(self):
        if self.device_open:
            in_tuple = self.board.dio_input_read_tuple()
            for index in range(mcc152.info().NUM_DIO_CHANNELS):
                if in_tuple[index] == 0:
                    self.in_states[index].config(text='0')
                else:
                    self.in_states[index].config(text='1')

            # schedule another update in 200 ms
            self.master.after(200, self.updateInputs)
Exemplo n.º 7
0
def main():
    """
    This function is executed automatically when the module is run directly.
    """
    options = OptionFlags.DEFAULT
    channel = 0
    num_channels = mcc152.info().NUM_AO_CHANNELS

    # Ensure channel is valid.
    if channel not in range(num_channels):
        error_message = ('Error: Invalid channel selection - must be '
                         '0 - {}'.format(num_channels - 1))
        raise Exception(error_message)

    print('MCC 152 single channel analog output example.')
    print('Writes the specified voltage to the analog output.')
    print("   Methods demonstrated:")
    print("      mcc152.a_out_write")
    print("      mcc152.info")
    print("   Channel: {}\n".format(channel))

    # Get an instance of the selected hat device object.
    address = select_hat_device(HatIDs.MCC_152)

    print("\nUsing address {}.\n".format(address))

    hat = mcc152(address)

    run_loop = True
    error = False
    while run_loop and not error:
        # Get the value from the user.
        try:
            value = get_input_value()
        except ValueError:
            run_loop = False
        else:
            # Write the value to the selected channel.
            try:
                hat.a_out_write(channel=channel,
                                value=value,
                                options=options)
            except (HatError, ValueError):
                error = True

    if error:
        print("Error writing analog output.")
Exemplo n.º 8
0
    def __init__(self, master):
        self.master = master
        master.title("MCC 152 Control Panel")

        # Initialize variables
        self.device_open = False
        self.open_address = 0
        self.board = None

        # GUI Setup

        self.bold_font = tkinter.font.Font(
            family=tkinter.font.nametofont("TkDefaultFont")["family"],
            size=tkinter.font.nametofont("TkDefaultFont")["size"],
            weight="bold")

        # Create and organize frames
        self.top_frame = tkinter.LabelFrame(master, text="Select Device")
        self.top_frame.pack(side=tkinter.TOP, expand=False, fill=tkinter.X)

        self.left_frame = tkinter.LabelFrame(master, text="Digital I/O")
        self.left_frame.pack(side=tkinter.LEFT, expand=True, fill=tkinter.BOTH)

        self.right_frame = tkinter.LabelFrame(master, text="Analog Output")
        self.right_frame.pack(side=tkinter.RIGHT, fill=tkinter.Y)

        # Create widgets

        self.dev_label = tkinter.Label(self.top_frame, text="MCC 152 address:")
        self.dev_label.grid(row=0, column=0)

        self.open_button = tkinter.Button(self.top_frame,
                                          text="Open",
                                          width=6,
                                          command=self.pressed_open_button)

        # Get list of MCC 152 devices for the device list widget
        self.addr_list = self.list_devices()

        if not self.addr_list:
            self.device_lister = tkinter.Label(self.top_frame,
                                               text="None found")
            self.open_button.config(state=tkinter.DISABLED)
        else:
            self.device_variable = tkinter.StringVar(self.top_frame)
            self.device_variable.set(self.addr_list[0])
            self.device_lister = tkinter.OptionMenu(self.top_frame,
                                                    self.device_variable,
                                                    *self.addr_list)

        self.device_lister.grid(row=0, column=1)
        self.open_button.grid(row=0, column=2)

        self.col_labels = []
        self.col_labels.append(
            tkinter.Label(self.left_frame,
                          text="DIO #",
                          font=self.bold_font,
                          padx=3))
        self.col_labels.append(
            tkinter.Label(self.left_frame,
                          text="Direction",
                          font=self.bold_font,
                          padx=3))
        self.col_labels.append(
            tkinter.Label(self.left_frame,
                          text="Input State",
                          font=self.bold_font,
                          padx=3))
        self.col_labels.append(
            tkinter.Label(self.left_frame,
                          text="Output State",
                          font=self.bold_font,
                          padx=3))
        self.col_labels[0].grid(row=0, column=0)
        self.col_labels[1].grid(row=0, column=1)
        self.col_labels[2].grid(row=0, column=2)
        self.col_labels[3].grid(row=0, column=3)
        self.left_frame.grid_columnconfigure(0, weight=1)
        self.left_frame.grid_columnconfigure(1, weight=1)
        self.left_frame.grid_columnconfigure(2, weight=1)
        self.left_frame.grid_columnconfigure(3, weight=1)

        self.dio_labels = []
        self.dirs = []
        self.in_states = []
        self.out_states = []
        for index in range(mcc152.info().NUM_DIO_CHANNELS):
            # Labels
            self.dio_labels.append(
                tkinter.Label(self.left_frame, text="{}".format(index)))
            self.dio_labels[index].grid(row=index + 1, column=0)

            self.dirs.append(
                tkinter.Button(self.left_frame,
                               text="Input",
                               width=6,
                               command=lambda index=index: self.
                               pressed_dir_button(index)))
            self.dirs[index].grid(row=index + 1, column=1)

            self.in_states.append(tkinter.Label(self.left_frame, text="1"))
            self.in_states[index].grid(row=index + 1, column=2)

            self.out_states.append(
                tkinter.Button(self.left_frame,
                               text="1",
                               command=lambda index=index: self.
                               pressed_output_button(index)))
            self.out_states[index].grid(row=index + 1, column=3)

            self.left_frame.grid_rowconfigure(index + 1, weight=1)

        self.aout_sliders = []
        for index in range(mcc152.info().NUM_AO_CHANNELS):
            self.aout_sliders.append(
                tkinter.Scale(self.right_frame,
                              from_=5.0,
                              to=0.0,
                              resolution=0.1,
                              label="Ch {}".format(index),
                              command=lambda value, index=index: self.
                              set_aout_value(index, value)))
            self.aout_sliders[index].grid(row=0, column=index)
            self.aout_sliders[index].grid_configure(sticky="nsew")

        self.right_frame.grid_rowconfigure(0, weight=1)
        self.right_frame.grid_columnconfigure(0, weight=1)
        self.right_frame.grid_columnconfigure(1, weight=1)

        # Disable widgets until a device is opened
        self.disable_controls()

        master.protocol('WM_DELETE_WINDOW', self.close)  # exit cleanup

        icon = tkinter.PhotoImage(file='/usr/share/mcc/daqhats/icon.png')
        # pylint: disable=protected-access
        master.tk.call('wm', 'iconphoto', master._w, icon)
Exemplo n.º 9
0
    def __init__(self, master):
        self.master = master
        master.title("MCC 152 CE Test")

        # Initialize variables
        self.device_open = False
        self.board = None
        self.voltage_limit = DEFAULT_V_LIMIT
        self.ao_voltage = mcc152.info().AO_MAX_VOLTAGE
        self.test_count = 0
        self.software_errors = 0
        self.baseline_set = False
        self.watchdog_count = 0
        self.csvfile = None
        self.id = None
        self.activity_id = None
        self.d_out_values = [0] * 4
        self.d_in_values = [0] * 4

        self.dmm = DMM()

        # GUI Setup

        # Device Frame
        self.device_frame = LabelFrame(master, text="Device status")
        #self.device_frame.pack(side=TOP, expand=False, fill=X)
        self.device_frame.grid(row=0, column=0, padx=3, pady=3, sticky="NSEW")

        # Device widgets
        label = Label(self.device_frame, text="Serial number:")
        label.grid(row=0, column=0, padx=3, pady=3, sticky="E")
        self.serial_number = StringVar(self.device_frame, "00000000")
        label = Label(self.device_frame,
                      width=8,
                      textvariable=self.serial_number,
                      relief=SUNKEN)
        label.grid(row=0, column=1, padx=3, pady=3, ipadx=2, ipady=2)

        label = Label(self.device_frame, text="Software errors:")
        label.grid(row=1, column=0, padx=3, pady=3, sticky="E")
        self.software_error_label = Label(self.device_frame,
                                          width=8,
                                          text="0",
                                          relief=SUNKEN,
                                          anchor=E)
        self.software_error_label.grid(row=1,
                                       column=1,
                                       padx=3,
                                       pady=3,
                                       ipadx=2,
                                       ipady=2)

        label = Label(self.device_frame, text="Ready:")
        label.grid(row=0, column=3, padx=3, pady=3, sticky="E")
        self.ready_led = LED(self.device_frame, size=20)
        self.ready_led.grid(row=0, column=4, padx=3, pady=3)

        label = Label(self.device_frame, text="Activity:")
        label.grid(row=1, column=3, padx=3, pady=3, sticky="E")
        self.activity_led = LED(self.device_frame, size=20)
        self.activity_led.grid(row=1, column=4, padx=3, pady=3)

        # empty column for stretching
        self.device_frame.grid_columnconfigure(2, weight=1)

        # Test Frame
        self.test_frame = LabelFrame(master, text="Test setup")
        self.test_frame.grid(row=0,
                             column=1,
                             rowspan=2,
                             sticky="NEW",
                             padx=3,
                             pady=3)

        # Test widgets
        label = Label(self.test_frame, text="Pass/fail (latch):")
        label.grid(row=0, column=0, padx=3, pady=3, sticky="W")
        self.pass_led = LED(self.test_frame, size=20)
        self.pass_led.grid(row=0, column=1, padx=3, pady=3)

        label = Label(self.test_frame, text="Pass/fail (inst):")
        label.grid(row=1, column=0, padx=3, pady=3, sticky="W")
        self.inst_pass_led = LED(self.test_frame, size=20)
        self.inst_pass_led.grid(row=1, column=1, padx=3, pady=3)

        label = Label(self.test_frame, text="Test count:")
        label.grid(row=2, column=0, padx=3, pady=3, sticky="W")
        self.test_count_label = Label(self.test_frame,
                                      width=8,
                                      text="0",
                                      relief=SUNKEN,
                                      anchor=E)
        self.test_count_label.grid(row=2,
                                   column=1,
                                   padx=3,
                                   pady=3,
                                   ipadx=2,
                                   ipady=2)

        self.start_button = Button(self.test_frame,
                                   text="Start",
                                   command=self.startTest)
        self.start_button.grid(row=0, column=2, padx=3, pady=3)

        style = Style()
        style.configure("C.TButton", foreground='red')
        self.stop_button = Button(
            self.test_frame,
            text="Stop",
            style="C.TButton",  #foreground="red",
            command=self.stopTest,
            state=DISABLED)
        self.stop_button.grid(row=1, column=2, padx=3, pady=3, sticky="NSEW")

        self.reset_button = Button(self.test_frame,
                                   text="Reset",
                                   command=self.resetTest)
        self.reset_button.grid(row=2, column=2, padx=3, pady=3, sticky="NSEW")

        v = IntVar()
        self.watchdog_check = Checkbutton(self.test_frame,
                                          text="Use watchdog",
                                          variable=v)
        self.watchdog_check.var = v
        self.watchdog_check.grid(row=3,
                                 column=0,
                                 columnspan=2,
                                 padx=3,
                                 pady=3,
                                 sticky="W")

        # Digital I/O Frame
        self.dio_frame = LabelFrame(master, text="Digital I/O Loopback")
        self.dio_frame.grid(row=1,
                            rowspan=2,
                            column=0,
                            sticky="NSEW",
                            padx=3,
                            pady=3)

        # Widgets
        label = Label(self.dio_frame, text="Limit: No mismatch")
        label.grid(row=0, column=0, columnspan=6, padx=3, pady=3, sticky="W")

        label = Label(self.dio_frame, text="Channel")
        label.grid(row=1, column=0, padx=3, pady=3)
        label = Label(self.dio_frame, text="State")
        label.grid(row=1, column=1, padx=3, pady=3)
        label = Label(self.dio_frame, text="Value")
        label.grid(row=1, column=2, padx=3, pady=3)
        label = Label(self.dio_frame, text="Channel")
        label.grid(row=1, column=3, padx=3, pady=3)
        label = Label(self.dio_frame, text="State")
        label.grid(row=1, column=4, padx=3, pady=3)
        label = Label(self.dio_frame, text="Value")
        label.grid(row=1, column=5, padx=3, pady=3)
        label = Label(self.dio_frame, text="Failures")
        label.grid(row=1, column=6, padx=3, pady=3)

        self.dio_failure_labels = []
        self.d_out_labels = []
        self.d_in_labels = []

        for channel in range(4):
            label = Label(self.dio_frame, text=channel)
            label.grid(row=2 + channel, column=0, padx=3, pady=3)
            label = Label(self.dio_frame, text=channel + 4)
            label.grid(row=2 + channel, column=3, padx=3, pady=3)

            label = Label(self.dio_frame,
                          text="Out",
                          width=4,
                          anchor=CENTER,
                          relief=SUNKEN)
            label.grid(row=2 + channel,
                       column=1,
                       padx=3,
                       pady=3,
                       ipadx=2,
                       ipady=2)

            self.d_out_labels.append(
                Label(self.dio_frame,
                      text="",
                      width=3,
                      anchor=CENTER,
                      relief=SUNKEN))
            self.d_out_labels[channel].grid(row=2 + channel,
                                            column=2,
                                            padx=3,
                                            pady=3,
                                            ipadx=2,
                                            ipady=2)

            label = Label(self.dio_frame,
                          text="In",
                          width=4,
                          anchor=CENTER,
                          relief=SUNKEN)
            label.grid(row=2 + channel,
                       column=4,
                       padx=3,
                       pady=3,
                       ipadx=2,
                       ipady=2)

            self.d_in_labels.append(
                Label(self.dio_frame,
                      text="",
                      width=3,
                      anchor=CENTER,
                      relief=SUNKEN))
            self.d_in_labels[channel].grid(row=2 + channel,
                                           column=5,
                                           padx=3,
                                           pady=3,
                                           ipadx=2,
                                           ipady=2)

            self.dio_failure_labels.append(
                Label(self.dio_frame,
                      width=8,
                      anchor=E,
                      relief=SUNKEN,
                      text="0"))
            self.dio_failure_labels[channel].grid(row=2 + channel,
                                                  column=6,
                                                  padx=3,
                                                  pady=3,
                                                  ipadx=2,
                                                  ipady=2)

        # Output Voltage Frame
        self.volt_frame = LabelFrame(master, text="Voltage Output")
        #self.tc_frame.pack(side=BOTTOM, expand=True, fill=BOTH)
        self.volt_frame.grid(row=2, column=1, sticky="NSEW", padx=3, pady=3)

        # Voltage widgets
        label = Label(self.volt_frame, text="Limit: ±")
        label.grid(row=0, column=0, padx=3, pady=3, sticky="W")
        label = Label(self.volt_frame,
                      text="{:.1f} mV".format(self.voltage_limit),
                      relief=SUNKEN,
                      anchor=E,
                      width=10)
        label.grid(row=0, column=1, padx=3, pady=3, ipadx=2, ipady=2)

        label = Label(self.volt_frame, text="Output, V")
        label.grid(row=1, column=0, padx=3, pady=3)
        label = Label(self.volt_frame, text="Error, mV")
        label.grid(row=1, column=1, padx=3, pady=3)
        label = Label(self.volt_frame, text="Failures")
        label.grid(row=1, column=2, padx=3, pady=3)

        self.voltage_label = None
        self.error_voltage_label = None
        self.ao_failure_label = None

        # Voltage
        self.voltage_label = Label(self.volt_frame,
                                   anchor=E,
                                   width=10,
                                   text="",
                                   relief=SUNKEN)
        self.voltage_label.grid(row=2,
                                column=0,
                                padx=3,
                                pady=3,
                                ipadx=2,
                                ipady=2)

        self.error_voltage_label = Label(self.volt_frame,
                                         anchor=E,
                                         width=10,
                                         text="",
                                         relief=SUNKEN)
        self.error_voltage_label.grid(row=2,
                                      column=1,
                                      padx=3,
                                      pady=3,
                                      ipadx=2,
                                      ipady=2)
        #self.voltage_label.grid_configure(sticky="E")

        self.ao_failure_label = Label(self.volt_frame,
                                      anchor=E,
                                      width=10,
                                      relief=SUNKEN,
                                      text="0")
        self.ao_failure_label.grid(row=2,
                                   column=2,
                                   padx=3,
                                   pady=3,
                                   ipadx=2,
                                   ipady=2)

        self.volt_frame.grid_columnconfigure(0, weight=1)
        self.volt_frame.grid_columnconfigure(1, weight=1)
        self.volt_frame.grid_columnconfigure(2, weight=1)

        master.protocol('WM_DELETE_WINDOW', self.close)  # exit cleanup

        icon = PhotoImage(file='/usr/share/mcc/daqhats/icon.png')
        master.tk.call('wm', 'iconphoto', master._w, icon)

        self.pass_led.set(1)
Exemplo n.º 10
0
    Purpose:
        Write values to both analog outputsin a loop.

    Description:
        This example demonstrates writing output data to both outputs
        simultaneously.
"""
from __future__ import print_function
from sys import version_info
from daqhats import mcc152, OptionFlags, HatIDs, HatError
from daqhats_utils import select_hat_device

# Get the min and max voltage values for the analog outputs to validate
# the user input.
MIN_V = mcc152.info().AO_MIN_RANGE
MAX_V = mcc152.info().AO_MAX_RANGE
NUM_CHANNELS = mcc152.info().NUM_AO_CHANNELS

def get_channel_value(channel):
    """
    Get the voltage from the user and validate it.
    """

    if channel not in range(NUM_CHANNELS):
        raise ValueError(
            "Channel must be in range 0 - {}.".format(NUM_CHANNELS - 1))

    while True:
        message = "   Channel {}: ".format(channel)
Exemplo n.º 11
0
    def __init__(self, master):
        self.master = master
        title = "MCC 152 Control Panel"
        master.title(title)

        # Initialize variables
        self.device_open = False
        self.open_address = 0
        self.board = None

        # GUI Setup
        titlefont = tkinter.font.Font(
            family=tkinter.font.nametofont("TkCaptionFont")["family"],
            size=tkinter.font.nametofont("TkCaptionFont")["size"],
            weight=tkinter.font.nametofont("TkCaptionFont")["weight"])
        titlewidth = titlefont.measure(title)
        master.minsize(titlewidth + 160, 0)

        master.resizable(False, False)

        self.BOLD_FONT = tkinter.font.Font(
            family=tkinter.font.nametofont("TkDefaultFont")["family"],
            size=tkinter.font.nametofont("TkDefaultFont")["size"],
            weight="bold")

        img = Image("photo", file="/usr/share/mcc/daqhats/icon.png")
        master.tk.call('wm', 'iconphoto', master._w, img)

        # Create and organize frames
        self.top_frame = LabelFrame(master, text="Select Device")
        self.top_frame.pack(side=TOP, expand=False, fill=X)

        self.left_frame = LabelFrame(master, text="Digital I/O")
        self.left_frame.pack(side=LEFT, expand=True, fill=BOTH)

        self.right_frame = LabelFrame(master, text="Analog Output")
        self.right_frame.pack(side=RIGHT, fill=Y)

        # Create widgets

        self.dev_label = Label(self.top_frame, text="MCC 152 address:")
        self.dev_label.grid(row=0, column=0)

        self.open_button = Button(self.top_frame,
                                  text="Open",
                                  width=6,
                                  command=self.pressedOpenButton)

        # Get list of MCC 152 devices for the device list widget
        self.addr_list = self.listDevices()

        if len(self.addr_list) == 0:
            self.device_lister = Label(self.top_frame, text="None found")
            self.open_button.config(state=DISABLED)
        else:
            self.device_variable = StringVar(self.top_frame)
            self.device_variable.set(self.addr_list[0])
            self.device_lister = OptionMenu(self.top_frame,
                                            self.device_variable,
                                            *self.addr_list)

        self.device_lister.grid(row=0, column=1)
        self.open_button.grid(row=0, column=2)

        self.col_labels = []
        self.col_labels.append(
            Label(self.left_frame, text="DIO #", font=self.BOLD_FONT, padx=3))
        self.col_labels.append(
            Label(self.left_frame,
                  text="Direction",
                  font=self.BOLD_FONT,
                  padx=3))
        self.col_labels.append(
            Label(self.left_frame,
                  text="Input State",
                  font=self.BOLD_FONT,
                  padx=3))
        self.col_labels.append(
            Label(self.left_frame,
                  text="Output State",
                  font=self.BOLD_FONT,
                  padx=3))
        self.col_labels[0].grid(row=0, column=0)
        self.col_labels[1].grid(row=0, column=1)
        self.col_labels[2].grid(row=0, column=2)
        self.col_labels[3].grid(row=0, column=3)
        self.left_frame.grid_columnconfigure(0, weight=1)
        self.left_frame.grid_columnconfigure(1, weight=1)
        self.left_frame.grid_columnconfigure(2, weight=1)
        self.left_frame.grid_columnconfigure(3, weight=1)

        self.dio_labels = []
        self.dirs = []
        self.in_states = []
        self.out_states = []
        for index in range(mcc152.info().NUM_DIO_CHANNELS):
            # Labels
            self.dio_labels.append(
                Label(self.left_frame, text="{}".format(index)))
            self.dio_labels[index].grid(row=index + 1, column=0)

            self.dirs.append(
                Button(
                    self.left_frame,
                    text="Input",
                    width=6,
                    command=lambda index=index: self.pressedDirButton(index)))
            self.dirs[index].grid(row=index + 1, column=1)

            self.in_states.append(Label(self.left_frame, text="1"))
            self.in_states[index].grid(row=index + 1, column=2)

            self.out_states.append(
                Button(self.left_frame,
                       text="1",
                       command=lambda index=index: self.pressedOutputButton(
                           index)))
            self.out_states[index].grid(row=index + 1, column=3)

            self.left_frame.grid_rowconfigure(index + 1, weight=1)

        self.aout_sliders = []
        for index in range(mcc152.info().NUM_AO_CHANNELS):
            self.aout_sliders.append(
                Scale(self.right_frame,
                      from_=5.0,
                      to=0.0,
                      resolution=0.1,
                      label="Ch {}".format(index),
                      command=lambda value, index=index: self.setAoutValue(
                          index, value)))
            self.aout_sliders[index].grid(row=0, column=index)
            self.aout_sliders[index].grid_configure(sticky="nsew")

        self.right_frame.grid_rowconfigure(0, weight=1)
        self.right_frame.grid_columnconfigure(0, weight=1)
        self.right_frame.grid_columnconfigure(1, weight=1)

        # Disable widgets until a device is opened
        self.disableControls()

        master.protocol('WM_DELETE_WINDOW', self.close)  # exit cleanup