Example #1
0
def run_example():
    # By default, the example detects and displays all available devices and
    # selects the first device listed. Use the dev_id_list variable to filter
    # detected devices by device ID (see UL documentation for device IDs).
    # If use_device_detection is set to False, the board_num variable needs to
    # match the desired board number configured with Instacal.
    use_device_detection = True
    dev_id_list = []
    board_num = 0

    try:
        if use_device_detection:
            config_first_detected_device(board_num, dev_id_list)

        daq_dev_info = DaqDeviceInfo(board_num)
        if not daq_dev_info.supports_analog_input:
            raise Exception('Error: The DAQ device does not support '
                            'analog input')

        print('\nActive DAQ device: ',
              daq_dev_info.product_name,
              ' (',
              daq_dev_info.unique_id,
              ')\n',
              sep='')

        ai_info = daq_dev_info.get_ai_info()
        ai_range = ai_info.supported_ranges[0]
        channel = 0

        # Get a value from the device
        if ai_info.resolution <= 16:
            # Use the a_in method for devices with a resolution <= 16
            value = ul.a_in(board_num, channel, ai_range)
            # Convert the raw value to engineering units
            eng_units_value = ul.to_eng_units(board_num, ai_range, value)
        else:
            # Use the a_in_32 method for devices with a resolution > 16
            # (optional parameter omitted)
            value = ul.a_in_32(board_num, channel, ai_range)
            # Convert the raw value to engineering units
            eng_units_value = ul.to_eng_units_32(board_num, ai_range, value)

        # Display the raw value
        print('Raw Value:', value)
        # Display the engineering value
        print('Engineering Value: {:.3f}'.format(eng_units_value))
    except Exception as e:
        print('\n', e)
    finally:
        if use_device_detection:
            ul.release_daq_device(board_num)
Example #2
0
def run_example():
    # By default, the example detects and displays all available devices and
    # selects the first device listed. Use the dev_id_list variable to filter
    # detected devices by device ID (see UL documentation for device IDs).
    # If use_device_detection is set to False, the board_num variable needs to
    # match the desired board number configured with Instacal.
    use_device_detection = True
    dev_id_list = []
    board_num = 0

    try:
        if use_device_detection:
            config_first_detected_device(board_num, dev_id_list)

        daq_dev_info = DaqDeviceInfo(board_num)
        if not daq_dev_info.supports_analog_input:
            raise Exception('Error: The DAQ device does not support '
                            'analog input')

        print('\nActive DAQ device: ',
              daq_dev_info.product_name,
              ' (',
              daq_dev_info.unique_id,
              ')\n',
              sep='')

        ai_info = daq_dev_info.get_ai_info()
        if ai_info.num_temp_chans <= 0:
            raise Exception('Error: The DAQ device does not support '
                            'temperature input')
        channel = 0

        # Get the value from the device (optional parameters omitted)
        value = ul.t_in(board_num, channel, TempScale.CELSIUS)

        # Display the value
        print('Channel', channel, 'Value (deg C):', value)
    except Exception as e:
        print('\n', e)
    finally:
        if use_device_detection:
            ul.release_daq_device(board_num)
Example #3
0
class ULAI15(UIExample):
    def __init__(self, master=None):
        super(ULAI15, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        use_device_detection = True
        self.board_num = 0

        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            self.ai_info = self.device_info.get_ai_info()
            example_supported = (self.ai_info.is_supported
                                 and self.ai_info.supports_scan
                                 and ScanOptions.SCALEDATA in
                                 self.ai_info.supported_scan_options)
            if example_supported:
                self.create_widgets()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets(True)

    def start_scan(self):
        low_chan = self.get_low_channel_num()
        high_chan = self.get_high_channel_num()

        if low_chan > high_chan:
            messagebox.showerror(
                "Error",
                "Low Channel Number must be greater than or equal to High "
                "Channel Number")
            self.start_button["state"] = tk.NORMAL
            return

        rate = 100
        points_per_channel = 10
        num_channels = high_chan - low_chan + 1
        total_count = points_per_channel * num_channels

        range_ = self.ai_info.supported_ranges[0]

        # Allocate a buffer for the scan
        memhandle = ul.scaled_win_buf_alloc(total_count)

        # Check if the buffer was successfully allocated
        if not memhandle:
            messagebox.showerror("Error", "Failed to allocate memory")
            self.start_button["state"] = tk.NORMAL
            return

        # Convert the memhandle to a ctypes array
        # Note: the ctypes array will only be valid until win_buf_free
        # is called.
        # A copy of the buffer can be created using scaled_win_buf_to_array
        # before the memory is freed. The copy can be used at any time.
        array = cast(memhandle, POINTER(c_double))

        try:
            # Run the scan
            ul.a_in_scan(self.board_num, low_chan, high_chan, total_count,
                         rate, range_, memhandle, ScanOptions.SCALEDATA)

            # Display the values
            self.display_values(array, total_count, low_chan, high_chan)
        except ULError as e:
            show_ul_error(e)
        finally:
            # Free the allocated memory
            ul.win_buf_free(memhandle)
            self.start_button["state"] = tk.NORMAL

    def display_values(self, array, total_count, low_chan, high_chan):
        new_data_frame = tk.Frame(self.results_group)

        channel_text = []

        # Add the headers
        for chan_num in range(low_chan, high_chan + 1):
            channel_text.append("Channel " + str(chan_num) + "\n")

        chan_count = high_chan - low_chan + 1

        # Add (up to) the first 10 values for each channel to the text
        chan_num = low_chan
        for data_index in range(0, min(chan_count * 10, total_count)):
            channel_text[chan_num - low_chan] += (
                '{:.3f}'.format(array[data_index]) + "\n")
            chan_num = low_chan if chan_num == high_chan else chan_num + 1

        # Add the labels for each channel
        for chan_num in range(low_chan, high_chan + 1):
            chan_label = tk.Label(new_data_frame, justify=tk.LEFT, padx=3)
            chan_label["text"] = channel_text[chan_num - low_chan]
            chan_label.grid(row=0, column=chan_num - low_chan)

        self.data_frame.destroy()
        self.data_frame = new_data_frame
        self.data_frame.grid()

    def start(self):
        self.start_button["state"] = tk.DISABLED
        self.start_scan()

    def get_low_channel_num(self):
        if self.ai_info.num_chans == 1:
            return 0
        try:
            return int(self.low_channel_entry.get())
        except ValueError:
            return 0

    def get_high_channel_num(self):
        if self.ai_info.num_chans == 1:
            return 0
        try:
            return int(self.high_channel_entry.get())
        except ValueError:
            return 0

    def validate_channel_entry(self, p):
        if p == '':
            return True
        try:
            value = int(p)
            if value < 0 or value > self.ai_info.num_chans - 1:
                return False
        except ValueError:
            return False

        return True

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num)
                                     + ": " + self.device_info.product_name
                                     + " (" + self.device_info.unique_id + ")")

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)

        curr_row = 0
        if self.ai_info.num_chans > 1:
            channel_vcmd = self.register(self.validate_channel_entry)

            low_channel_entry_label = tk.Label(main_frame)
            low_channel_entry_label["text"] = "Low Channel Number:"
            low_channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.low_channel_entry = tk.Spinbox(
                main_frame, from_=0,
                to=max(self.ai_info.num_chans - 1, 0),
                validate='key', validatecommand=(channel_vcmd, '%P'))
            self.low_channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)

            curr_row += 1
            high_channel_entry_label = tk.Label(main_frame)
            high_channel_entry_label["text"] = "High Channel Number:"
            high_channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.high_channel_entry = tk.Spinbox(
                main_frame, from_=0, validate='key',
                to=max(self.ai_info.num_chans - 1, 0),
                validatecommand=(channel_vcmd, '%P'))
            self.high_channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)
            initial_value = min(self.ai_info.num_chans - 1, 3)
            self.high_channel_entry.delete(0, tk.END)
            self.high_channel_entry.insert(0, str(initial_value))

            curr_row += 1

        self.results_group = tk.LabelFrame(
            self, text="Results", padx=3, pady=3)
        self.results_group.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.data_frame = tk.Frame(self.results_group)
        self.data_frame.grid()

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.start_button = tk.Button(button_frame)
        self.start_button["text"] = "Start"
        self.start_button["command"] = self.start
        self.start_button.grid(row=0, column=0, padx=3, pady=3)

        quit_button = tk.Button(button_frame)
        quit_button["text"] = "Quit"
        quit_button["command"] = self.master.destroy
        quit_button.grid(row=0, column=1, padx=3, pady=3)
Example #4
0
class ULAI03(UIExample):
    def __init__(self, master=None):
        super(ULAI03, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        use_device_detection = True
        self.board_num = 0

        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            self.ai_info = self.device_info.get_ai_info()
            if self.ai_info.is_supported and self.ai_info.supports_scan:
                self.create_widgets()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets()

    def start_scan(self):
        self.low_chan = self.get_low_channel_num()
        self.high_chan = self.get_high_channel_num()
        self.num_chans = self.high_chan - self.low_chan + 1
        if self.low_chan > self.high_chan:
            messagebox.showerror(
                "Error",
                "Low Channel Number must be greater than or equal to High "
                "Channel Number")
            self.set_ui_idle_state()
            return

        rate = 100
        points_per_channel = 1000
        total_count = points_per_channel * self.num_chans
        ai_range = self.ai_info.supported_ranges[0]

        # Allocate a buffer for the scan
        if self.ai_info.resolution <= 16:
            # Use the win_buf_alloc method for devices with a resolution <=
            # 16
            self.memhandle = ul.win_buf_alloc(total_count)
            # Convert the memhandle to a ctypes array
            # Use the memhandle_as_ctypes_array method for devices with a
            # resolution <= 16
            self.ctypes_array = cast(self.memhandle, POINTER(c_ushort))
        else:
            # Use the win_buf_alloc_32 method for devices with a resolution
            # > 16
            self.memhandle = ul.win_buf_alloc_32(total_count)
            # Use the memhandle_as_ctypes_array_32 method for devices with a
            # resolution > 16
            self.ctypes_array = cast(self.memhandle, POINTER(c_ulong))

        # Note: the ctypes array will no longer be valid after
        # win_buf_free is called.
        # A copy of the buffer can be created using win_buf_to_array
        # or win_buf_to_array_32 before the memory is freed. The copy
        # can be used at any time.

        # Check if the buffer was successfully allocated
        if not self.memhandle:
            messagebox.showerror("Error", "Failed to allocate memory")
            self.set_ui_idle_state()
            return

        # Create the frames that will hold the data
        self.recreate_data_frame()

        try:
            # Start the scan
            ul.a_in_scan(self.board_num, self.low_chan, self.high_chan,
                         total_count, rate, ai_range, self.memhandle,
                         ScanOptions.BACKGROUND)
        except ULError as e:
            show_ul_error(e)
            self.set_ui_idle_state()
            return

        # Start updating the displayed values
        self.update_displayed_values()

    def update_displayed_values(self):
        # Get the status from the device
        status, curr_count, curr_index = ul.get_status(self.board_num,
                                                       FunctionType.AIFUNCTION)

        # Display the status info
        self.update_status_labels(status, curr_count, curr_index)

        # Display the values
        self.display_values(curr_index, curr_count)

        # Call this method again until the stop button is pressed
        if status == Status.RUNNING:
            self.after(100, self.update_displayed_values)
        else:
            # Free the allocated memory
            ul.win_buf_free(self.memhandle)
            # Stop the background operation (this is required even if the
            # scan completes successfully)
            ul.stop_background(self.board_num, FunctionType.AIFUNCTION)
            self.set_ui_idle_state()

    def update_status_labels(self, status, curr_count, curr_index):
        if status == Status.IDLE:
            self.status_label["text"] = "Idle"
        else:
            self.status_label["text"] = "Running"

        self.index_label["text"] = str(curr_index)
        self.count_label["text"] = str(curr_count)

    def display_values(self, curr_index, curr_count):
        per_channel_display_count = 10
        array = self.ctypes_array
        low_chan = self.low_chan
        high_chan = self.high_chan
        channel_text = []

        # Add the headers
        for chan_num in range(low_chan, high_chan + 1):
            channel_text.append("Channel " + str(chan_num) + "\n")

        # If no data has been gathered, don't add data to the labels
        if curr_count > 1:
            chan_count = high_chan - low_chan + 1

            chan_num = low_chan
            # curr_index points to the start of the last completed channel
            # scan that was transferred between the board and the data
            # buffer. Based on this, calculate the first index we want to
            # display using subtraction.
            first_index = max(curr_index - ((per_channel_display_count - 1)
                                            * chan_count), 0)
            last_index = first_index + min(chan_count
                                           * per_channel_display_count,
                                           curr_count)
            # Add (up to) the latest 10 values for each channel to the text
            for data_index in range(first_index, last_index):
                channel_text[chan_num - low_chan] += (str(array[data_index])
                                                      + "\n")
                chan_num = low_chan if chan_num == high_chan else chan_num + 1

        # Update the labels for each channel
        for chan_num in range(low_chan, high_chan + 1):
            chan_index = chan_num - low_chan
            self.chan_labels[chan_index]["text"] = channel_text[chan_index]

    def recreate_data_frame(self):
        low_chan = self.low_chan
        high_chan = self.high_chan

        new_data_frame = tk.Frame(self.inner_data_frame)

        self.chan_labels = []
        # Add the labels for each channel
        for chan_num in range(low_chan, high_chan + 1):
            chan_label = tk.Label(new_data_frame, justify=tk.LEFT, padx=3)
            chan_label.grid(row=0, column=chan_num - low_chan)
            self.chan_labels.append(chan_label)

        self.data_frame.destroy()
        self.data_frame = new_data_frame
        self.data_frame.grid()

    def stop(self):
        ul.stop_background(self.board_num, FunctionType.AIFUNCTION)

    def set_ui_idle_state(self):
        self.high_channel_entry["state"] = tk.NORMAL
        self.low_channel_entry["state"] = tk.NORMAL
        self.start_button["command"] = self.start
        self.start_button["text"] = "Start"

    def start(self):
        self.high_channel_entry["state"] = tk.DISABLED
        self.low_channel_entry["state"] = tk.DISABLED
        self.start_button["command"] = self.stop
        self.start_button["text"] = "Stop"
        self.start_scan()

    def get_low_channel_num(self):
        if self.ai_info.num_chans == 1:
            return 0
        try:
            return int(self.low_channel_entry.get())
        except ValueError:
            return 0

    def get_high_channel_num(self):
        if self.ai_info.num_chans == 1:
            return 0
        try:
            return int(self.high_channel_entry.get())
        except ValueError:
            return 0

    def validate_channel_entry(self, p):
        if p == '':
            return True
        try:
            value = int(p)
            if value < 0 or value > self.ai_info.num_chans - 1:
                return False
        except ValueError:
            return False

        return True

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num)
                                     + ": " + self.device_info.product_name
                                     + " (" + self.device_info.unique_id + ")")

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)

        curr_row = 0
        if self.ai_info.num_chans > 1:
            channel_vcmd = self.register(self.validate_channel_entry)

            low_channel_entry_label = tk.Label(main_frame)
            low_channel_entry_label["text"] = "Low Channel Number:"
            low_channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.low_channel_entry = tk.Spinbox(
                main_frame, from_=0,
                to=max(self.ai_info.num_chans - 1, 0),
                validate='key', validatecommand=(channel_vcmd, '%P'))
            self.low_channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)

            curr_row += 1
            high_channel_entry_label = tk.Label(main_frame)
            high_channel_entry_label["text"] = "High Channel Number:"
            high_channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.high_channel_entry = tk.Spinbox(
                main_frame, from_=0, validate='key',
                to=max(self.ai_info.num_chans - 1, 0),
                validatecommand=(channel_vcmd, '%P'))
            self.high_channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)
            initial_value = min(self.ai_info.num_chans - 1, 3)
            self.high_channel_entry.delete(0, tk.END)
            self.high_channel_entry.insert(0, str(initial_value))

            curr_row += 1

        self.results_group = tk.LabelFrame(
            self, text="Results", padx=3, pady=3)
        self.results_group.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.results_group.grid_columnconfigure(1, weight=1)

        curr_row = 0
        status_left_label = tk.Label(self.results_group)
        status_left_label["text"] = "Status:"
        status_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.status_label = tk.Label(self.results_group)
        self.status_label["text"] = "Idle"
        self.status_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        index_left_label = tk.Label(self.results_group)
        index_left_label["text"] = "Index:"
        index_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.index_label = tk.Label(self.results_group)
        self.index_label["text"] = "-1"
        self.index_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        count_left_label = tk.Label(self.results_group)
        count_left_label["text"] = "Count:"
        count_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.count_label = tk.Label(self.results_group)
        self.count_label["text"] = "0"
        self.count_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        self.inner_data_frame = tk.Frame(self.results_group)
        self.inner_data_frame.grid(
            row=curr_row, column=0, columnspan=2, sticky=tk.W)

        self.data_frame = tk.Frame(self.inner_data_frame)
        self.data_frame.grid()

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.start_button = tk.Button(button_frame)
        self.start_button["text"] = "Start"
        self.start_button["command"] = self.start
        self.start_button.grid(row=0, column=0, padx=3, pady=3)

        self.quit_button = tk.Button(button_frame)
        self.quit_button["text"] = "Quit"
        self.quit_button["command"] = self.master.destroy
        self.quit_button.grid(row=0, column=1, padx=3, pady=3)
Example #5
0
class ULTI02(UIExample):
    def __init__(self, master):
        super(ULTI02, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        # BOARD NUMBER IS DEFINED IN TKINTER AT START OF TEST
        use_device_detection = False
        self.running = False
        # Device Detection not used in this test
        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            self.ai_info = self.device_info.get_ai_info()
            if self.ai_info.temp_supported:
                self.create_widgets()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets(True)

    # Main update loop that gets repeated every 100ms while the test is running
    def update_values(self):
        try:
            # Get the values from the device (optional parameters omitted)
            # Temp scale set to NOSCALE and conversion will be done via lookup table within this program
            err_code, data_array = ul.t_in_scan(self.board_num, 0, 7,
                                                TempScale.NOSCALE)

            # create array of temperature and resistances to be logged, data_array is raw resistance
            data_example = ""
            data_example_temps = ""
            data_temp_display = numpy.array(data_array)
            data_array = numpy.around(data_array, 3)
            temp_array = interp_resist_to_temp_np1000(data_array)
            for x in range(0, 8):
                data_example += str(data_array[x]) + ';'
                data_example_temps += str(
                    numpy.around(interp_resist_to_temp_np1000(data_array[x]),
                                 2)) + ';'

            # Check err_code for OUTOFRANGE or OPENCONNECTION. All other
            # error codes will raise a ULError and are checked by the except
            # clause.
            # if err_code == ErrorCode.OUTOFRANGE:
            #     self.warning_label["text"] = (
            #         "A thermocouple input is out of range.")
            # elif err_code == ErrorCode.OPENCONNECTION:
            #     self.warning_label["text"] = (
            #         "A thermocouple input has an open connection.")
            # else:
            #     self.warning_label["text"] = ""

            self.display_values(temp_array)

            # creates variables for time format in log
            current_date_and_time = datetime.datetime.now()
            current_date_and_time_string = current_date_and_time.strftime(
                "%Y-%m-%d %H:%M:%S")

            current_time = time.time()

            # start_logging Boolean is used to only log at 00 or 30 seconds of the minute
            # this is to have synched timings between two programs running independantly on the same machine
            sub_time = current_time - self.start_time
            seconds = datetime.datetime.now().strftime("%S")
            if seconds == '30' or seconds == '00':
                start_logging = True
            else:
                start_logging = False
            # Log at 00 or 30 seconds every minute (twice a minute)
            if sub_time >= 10 and start_logging:
                self.start_time = time.time()
                self.last_logged_time = datetime.datetime.now().strftime(
                    "%Y-%m-%d %H:%M:%S")
                # create log of temperature for the specified time
                try:
                    with open(self.filefullname, "a") as myfile:
                        myfile.write(current_date_and_time_string + ';')
                        myfile.write(data_example_temps + data_example + '\n')
                    myfile.close()
                except:
                    pass
            # Call this method again until the stop button is pressed (or an
            # error occurs)

            # This is the display in the command prompt
            message_timing = current_time - self.start_time_timing
            if message_timing <= 1 and self.verify == 1:
                os.system('cls')
                print('Test Running')
                print('Test Name =', self.test_name)
                print('Last logged data:', self.last_logged_time)
                for x in range(0, 8):
                    print(
                        round(
                            interp_resist_to_temp_np1000(data_temp_display[x]),
                            2), '°C', "\t", self.channel_list[x])
                self.verify = 2
            elif message_timing >= 1 and message_timing <= 2 and self.verify == 2:
                os.system('cls')
                print('Test Running.')
                print('Test Name =', self.test_name)
                print('Last logged data:', self.last_logged_time)
                for x in range(0, 8):
                    print(
                        round(
                            interp_resist_to_temp_np1000(data_temp_display[x]),
                            2), '°C', "\t", self.channel_list[x])
                self.verify = 3
            elif message_timing >= 2 and message_timing <= 3 and self.verify == 3:
                os.system('cls')
                print('Test Running..')
                print('Test Name =', self.test_name)
                print('Last logged data:', self.last_logged_time)
                for x in range(0, 8):
                    print(
                        round(
                            interp_resist_to_temp_np1000(data_temp_display[x]),
                            2), '°C', "\t", self.channel_list[x])
                self.verify = 4
            elif message_timing >= 3 and message_timing <= 4 and self.verify == 4:
                os.system('cls')
                print('Test Running...')
                print('Test Name =', self.test_name)
                print('Last logged data:', self.last_logged_time)
                for x in range(0, 8):
                    print(
                        round(
                            interp_resist_to_temp_np1000(data_temp_display[x]),
                            2), '°C', "\t", self.channel_list[x])
                self.verify = 5
            elif message_timing > 4 and self.verify == 5:
                self.start_time_timing = time.time()
                self.verify = 1
            else:
                pass

            # self-updating graph for easy visualisation

            # keep running after 100 ms if self.running is True
            if self.running:
                self.after(100, self.update_values)
        except ULError as e:
            self.stop()
            show_ul_error(e)

    def display_values(self, array):
        low_chan = 0
        high_chan = 7

        for chan_num in range(low_chan, high_chan + 1):
            index = chan_num - low_chan
            self.data_labels[index]["text"] = '{:.3f}'.format(
                array[index]) + "\n"

    def stop(self):
        self.running = False
        self.start_button["command"] = self.start
        self.start_button["text"] = "Start"
        # self.low_channel_entry["state"] = tk.NORMAL
        # self.high_channel_entry["state"] = tk.NORMAL

    def start(self):
        os.system('cls')
        self.running = True
        self.start_button["command"] = self.stop
        self.start_button["text"] = "Stop"
        # self.low_channel_entry["state"] = tk.DISABLED
        # self.high_channel_entry["state"] = tk.DISABLED
        self.test_name_entry["state"] = tk.DISABLED
        self.board_number_entry["state"] = tk.DISABLED
        # self.low_chan = self.get_low_channel_num()
        # self.high_chan = self.get_high_channel_num()
        self.test_name = self.get_test_name()
        self.channel0 = self.get_channel0()
        self.channel1 = self.get_channel1()
        self.channel2 = self.get_channel2()
        self.channel3 = self.get_channel3()
        self.channel4 = self.get_channel4()
        self.channel5 = self.get_channel5()
        self.channel6 = self.get_channel6()
        self.channel7 = self.get_channel7()
        self.channel_list = [
            self.channel0, self.channel1, self.channel2, self.channel3,
            self.channel4, self.channel5, self.channel6, self.channel7
        ]
        self.board_num = self.get_board_num()
        self.recreate_data_frame()
        self.start_time = time.time()
        self.start_time_timing = time.time()
        self.last_logged_time = 'Nothing logged yet'
        self.verify = 1
        self.inc = 0
        self.create_log_file()
        self.update_values()

    def create_log_file(self):
        # creates log_file when starting program
        if not os.path.exists('logs'):
            os.makedirs('logs')
        current_date_and_time = datetime.datetime.now()
        current_date_and_time_filename = current_date_and_time.strftime(
            "%Y_%m_%d-%H%M%S") + '_'
        dir = 'logs\\'
        filename = current_date_and_time_filename
        filemission = self.test_name
        file_ext = '.txt'
        self.filefullname = dir + filename + filemission + file_ext
        file = open(self.filefullname, 'a')

    # def get_low_channel_num(self):
    #     try:
    #         return int(self.low_channel_entry.get())
    #     except ValueError:
    #         return 0

    # def get_high_channel_num(self):
    #     try:
    #         return int(self.high_channel_entry.get())
    #     except ValueError:
    #         return 0

    def get_test_name(self):
        try:
            return self.test_name_entry.get("1.0", 'end-1c')
        except ValueError:
            return 0

    def get_channel0(self):
        try:
            return self.channel0_name_entry.get("1.0", 'end-1c')
        except ValueError:
            return 0

    def get_channel1(self):
        try:
            return self.channel1_name_entry.get("1.0", 'end-1c')
        except ValueError:
            return 0

    def get_channel2(self):
        try:
            return self.channel2_name_entry.get("1.0", 'end-1c')
        except ValueError:
            return 0

    def get_channel3(self):
        try:
            return self.channel3_name_entry.get("1.0", 'end-1c')
        except ValueError:
            return 0

    def get_channel4(self):
        try:
            return self.channel4_name_entry.get("1.0", 'end-1c')
        except ValueError:
            return 0

    def get_channel5(self):
        try:
            return self.channel5_name_entry.get("1.0", 'end-1c')
        except ValueError:
            return 0

    def get_channel6(self):
        try:
            return self.channel6_name_entry.get("1.0", 'end-1c')
        except ValueError:
            return 0

    def get_channel7(self):
        try:
            return self.channel7_name_entry.get("1.0", 'end-1c')
        except ValueError:
            return 0

    def get_board_num(self):
        try:
            return int(self.board_number_entry.get())
        except ValueError:
            return 0

    def validate_channel_entry(self, p):
        if p == '':
            return True
        try:
            value = int(p)
            if value < 0 or value > self.ai_info.num_temp_chans - 1:
                return False
        except ValueError:
            return False

        return True

    def recreate_data_frame(self):
        low_chan = 0
        high_chan = 7
        channels_per_row = 4

        new_data_frame = tk.Frame(self.results_group)

        self.data_labels = []
        row = 0
        column = 0
        # Add the labels for each channel
        for chan_num in range(low_chan, high_chan + 1):
            chan_label = tk.Label(new_data_frame, justify=tk.LEFT, padx=3)
            chan_label["text"] = "Channel " + str(chan_num)
            chan_label.grid(row=row, column=column)

            data_label = tk.Label(new_data_frame, justify=tk.LEFT, padx=3)
            data_label.grid(row=row + 1, column=column)
            self.data_labels.append(data_label)

            column += 1
            if column >= channels_per_row:
                row += 2
                column = 0

        self.data_frame.destroy()
        self.data_frame = new_data_frame
        self.data_frame.pack(side=tk.TOP)

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num) +
                                     ": " + self.device_info.product_name +
                                     " (" + self.device_info.unique_id + ")")

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)
        channel_vcmd = self.register(self.validate_channel_entry)

        curr_row = 0

        if self.ai_info.num_temp_chans > 1:

            # # Defining low channel entry

            # low_channel_entry_label = tk.Label(main_frame)
            # low_channel_entry_label["text"] = "Low Channel Number:"
            # low_channel_entry_label.grid(
            #     row=curr_row, column=0, sticky=tk.W)

            # self.low_channel_entry = tk.Spinbox(
            #     main_frame, from_=0,
            #     to=max(self.ai_info.num_temp_chans - 1, 0),
            #     validate='key', validatecommand=(channel_vcmd, '%P'))
            # self.low_channel_entry.grid(
            #     row=curr_row, column=1, sticky=tk.W)

            # # Defining high channel entry

            # curr_row += 1
            # high_channel_entry_label = tk.Label(main_frame)
            # high_channel_entry_label["text"] = "High Channel Number:"
            # high_channel_entry_label.grid(
            #     row=curr_row, column=0, sticky=tk.W)

            # self.high_channel_entry = tk.Spinbox(
            #     main_frame, from_=0,
            #     to=max(self.ai_info.num_temp_chans - 1, 0),
            #     validate='key', validatecommand=(channel_vcmd, '%P'))
            # self.high_channel_entry.grid(
            #     row=curr_row, column=1, sticky=tk.W)

            # Defining test name entry

            curr_row += 1
            test_name_entry_label = tk.Label(main_frame)
            test_name_entry_label["text"] = "Test Name"
            test_name_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.test_name_entry = tk.Text(main_frame, height=1, width=30)
            self.test_name_entry.grid(row=curr_row, column=1, sticky=tk.W)

            self.test_name_entry.insert(tk.END, 'Test Name')

            # Defining channel #0 name

            curr_row += 1
            channel0_name_entry_label = tk.Label(main_frame)
            channel0_name_entry_label["text"] = "Channel 0"
            channel0_name_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.channel0_name_entry = tk.Text(main_frame, height=1, width=30)
            self.channel0_name_entry.grid(row=curr_row, column=1, sticky=tk.W)
            self.channel0_name_entry.insert(tk.END, 'Channel 0')

            # Defining channel #1 name

            curr_row += 1
            channel1_name_entry_label = tk.Label(main_frame)
            channel1_name_entry_label["text"] = "Channel 1"
            channel1_name_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.channel1_name_entry = tk.Text(main_frame, height=1, width=30)
            self.channel1_name_entry.grid(row=curr_row, column=1, sticky=tk.W)
            self.channel1_name_entry.insert(tk.END, 'Channel 1')

            # Defining channel #2 name

            curr_row += 1
            channel2_name_entry_label = tk.Label(main_frame)
            channel2_name_entry_label["text"] = "Channel 2"
            channel2_name_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.channel2_name_entry = tk.Text(main_frame, height=1, width=30)
            self.channel2_name_entry.grid(row=curr_row, column=1, sticky=tk.W)
            self.channel2_name_entry.insert(tk.END, 'Channel 2')

            # Defining channel #3 name

            curr_row += 1
            channel3_name_entry_label = tk.Label(main_frame)
            channel3_name_entry_label["text"] = "Channel 3"
            channel3_name_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.channel3_name_entry = tk.Text(main_frame, height=1, width=30)
            self.channel3_name_entry.grid(row=curr_row, column=1, sticky=tk.W)
            self.channel3_name_entry.insert(tk.END, 'Channel 3')

            # Defining channel #4 name

            curr_row += 1
            channel4_name_entry_label = tk.Label(main_frame)
            channel4_name_entry_label["text"] = "Channel 4"
            channel4_name_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.channel4_name_entry = tk.Text(main_frame, height=1, width=30)
            self.channel4_name_entry.grid(row=curr_row, column=1, sticky=tk.W)
            self.channel4_name_entry.insert(tk.END, 'Channel 4')

            # Defining channel #5 name

            curr_row += 1
            channel5_name_entry_label = tk.Label(main_frame)
            channel5_name_entry_label["text"] = "Channel 5"
            channel5_name_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.channel5_name_entry = tk.Text(main_frame, height=1, width=30)
            self.channel5_name_entry.grid(row=curr_row, column=1, sticky=tk.W)
            self.channel5_name_entry.insert(tk.END, 'Channel 5')

            # Defining channel #6 name

            curr_row += 1
            channel6_name_entry_label = tk.Label(main_frame)
            channel6_name_entry_label["text"] = "Channel 6"
            channel6_name_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.channel6_name_entry = tk.Text(main_frame, height=1, width=30)
            self.channel6_name_entry.grid(row=curr_row, column=1, sticky=tk.W)
            self.channel6_name_entry.insert(tk.END, 'Channel 6')

            # Defining channel #7 name

            curr_row += 1
            channel7_name_entry_label = tk.Label(main_frame)
            channel7_name_entry_label["text"] = "Channel 7"
            channel7_name_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.channel7_name_entry = tk.Text(main_frame, height=1, width=30)
            self.channel7_name_entry.grid(row=curr_row, column=1, sticky=tk.W)
            self.channel7_name_entry.insert(tk.END, 'Channel 7')

            # Defining board number entry

            curr_row += 1
            board_number_entry_label = tk.Label(main_frame)
            board_number_entry_label["text"] = "Board number:"
            board_number_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.board_number_entry = tk.Spinbox(main_frame,
                                                 from_=0,
                                                 to=4,
                                                 validate='key',
                                                 validatecommand=(channel_vcmd,
                                                                  '%P'))
            self.board_number_entry.grid(row=curr_row, column=1, sticky=tk.W)

            # Default Values

            # initial_value = min(self.ai_info.num_temp_chans - 1, 7)
            # self.high_channel_entry.delete(0, tk.END)
            # self.high_channel_entry.insert(0, str(initial_value))

        self.results_group = tk.LabelFrame(self, text="Results")
        self.results_group.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.data_frame = tk.Frame(self.results_group)
        self.data_frame.pack(side=tk.TOP)

        self.warning_label = tk.Label(self.results_group, fg="red")
        self.warning_label.pack(side=tk.BOTTOM)

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.start_button = tk.Button(button_frame)
        self.start_button["text"] = "Start"
        self.start_button["command"] = self.start
        self.start_button.grid(row=0, column=0, padx=3, pady=3)

        quit_button = tk.Button(button_frame)
        quit_button["text"] = "Quit"
        quit_button["command"] = self.master.destroy
        quit_button.grid(row=0, column=1, padx=3, pady=3)
Example #6
0
class ULAIO01(UIExample):
    def __init__(self, master=None):
        super(ULAIO01, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        use_device_detection = True
        self.board_num = 0

        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            self.ai_info = self.device_info.get_ai_info()
            self.ao_info = self.device_info.get_ao_info()
            example_supported = (self.ai_info.is_supported
                                 and self.ai_info.supports_scan
                                 and self.ao_info.is_supported
                                 and self.ao_info.supports_scan)
            if example_supported:
                self.create_widgets()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets(True)

    def start_input_scan(self):
        self.input_low_chan = self.get_input_low_channel_num()
        self.input_high_chan = self.get_input_high_channel_num()
        self.num_input_chans = self.input_high_chan - self.input_low_chan + 1

        if self.input_low_chan > self.input_high_chan:
            messagebox.showerror(
                "Error",
                "Low Channel Number must be greater than or equal to High "
                "Channel Number")
            self.set_input_ui_idle_state()
            return

        rate = 100
        points_per_channel = 1000
        total_count = points_per_channel * self.num_input_chans
        range_ = self.ai_info.supported_ranges[0]
        scan_options = ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS

        # Allocate a buffer for the scan
        if self.ai_info.resolution <= 16:
            # Use the win_buf_alloc method for devices with a resolution <=
            # 16
            self.input_memhandle = ul.win_buf_alloc(total_count)
        else:
            # Use the win_buf_alloc_32 method for devices with a resolution
            # > 16
            self.input_memhandle = ul.win_buf_alloc_32(total_count)

        if not self.input_memhandle:
            messagebox.showerror("Error", "Failed to allocate memory")
            self.set_input_ui_idle_state()
            return

        # Create the frames that will hold the data
        self.recreate_input_data_frame()

        try:
            # Run the scan
            ul.a_in_scan(self.board_num, self.input_low_chan,
                         self.input_high_chan, total_count, rate, range_,
                         self.input_memhandle, scan_options)
        except ULError as e:
            show_ul_error(e)
            self.set_input_ui_idle_state()
            return

        # Convert the input_memhandle to a ctypes array
        # Note: the ctypes array will no longer be valid after win_buf_free is
        # called. A copy of the buffer can be created using win_buf_to_array
        # or win_buf_to_array_32 before the memory is freed. The copy can
        # be used at any time.
        if self.ai_info.resolution <= 16:
            # Use the memhandle_as_ctypes_array method for devices with a
            # resolution <= 16
            self.ctypes_array = cast(self.input_memhandle, POINTER(c_ushort))
        else:
            # Use the memhandle_as_ctypes_array_32 method for devices with a
            # resolution > 16
            self.ctypes_array = cast(self.input_memhandle, POINTER(c_ulong))

        # Start updating the displayed values
        self.update_input_displayed_values(range_)

    def update_input_displayed_values(self, range_):
        # Get the status from the device
        status, curr_count, curr_index = ul.get_status(self.board_num,
                                                       FunctionType.AIFUNCTION)

        # Display the status info
        self.update_input_status_labels(status, curr_count, curr_index)

        # Display the values
        self.display_input_values(range_, curr_index, curr_count)

        # Call this method again until the stop_input button is pressed
        if status == Status.RUNNING:
            self.after(100, self.update_input_displayed_values, range_)
        else:
            # Free the allocated memory
            ul.win_buf_free(self.input_memhandle)
            self.set_input_ui_idle_state()

    def update_input_status_labels(self, status, curr_count, curr_index):
        if status == Status.IDLE:
            self.input_status_label["text"] = "Idle"
        else:
            self.input_status_label["text"] = "Running"

        self.input_index_label["text"] = str(curr_index)
        self.input_count_label["text"] = str(curr_count)

    def display_input_values(self, range_, curr_index, curr_count):
        per_channel_display_count = 10
        array = self.ctypes_array
        low_chan = self.input_low_chan
        high_chan = self.input_high_chan
        channel_text = []

        # Add the headers
        for chan_num in range(low_chan, high_chan + 1):
            channel_text.append("Channel " + str(chan_num) + "\n")

        # If no data has been gathered, don't add data to the labels
        if curr_count > 1:
            chan_count = high_chan - low_chan + 1

            chan_num = low_chan
            # curr_index points to the start_input of the last completed
            # channel scan that was transferred between the board and the data
            # buffer. Based on this, calculate the first index we want to
            # display using subtraction.
            first_index = max(curr_index - ((per_channel_display_count - 1)
                                            * chan_count), 0)
            # Add (up to) the latest 10 values for each channel to the text
            for data_index in range(
                    first_index,
                    first_index + min(
                        chan_count * per_channel_display_count,
                        curr_count)):

                raw_value = array[data_index]
                if self.ai_info.resolution <= 16:
                    eng_value = ul.to_eng_units(self.board_num, range_,
                                                raw_value)
                else:
                    eng_value = ul.to_eng_units_32(self.board_num, range_,
                                                   raw_value)
                channel_text[chan_num - low_chan] += (
                    '{:.3f}'.format(eng_value) + "\n")
                chan_num = low_chan if chan_num == high_chan else chan_num + 1

        # Update the labels for each channel
        for chan_num in range(low_chan, high_chan + 1):
            chan_index = chan_num - low_chan
            self.chan_labels[chan_index]["text"] = channel_text[chan_index]

    def recreate_input_data_frame(self):
        low_chan = self.input_low_chan
        high_chan = self.input_high_chan

        new_data_frame = tk.Frame(self.input_inner_data_frame)

        self.chan_labels = []
        # Add the labels for each channel
        for chan_num in range(low_chan, high_chan + 1):
            chan_label = tk.Label(new_data_frame, justify=tk.LEFT, padx=3)
            chan_label.grid(row=0, column=chan_num - low_chan)
            self.chan_labels.append(chan_label)

        self.data_frame.destroy()
        self.data_frame = new_data_frame
        self.data_frame.grid()

    def exit(self):
        self.stop_input()
        self.stop_output()
        self.master.destroy()

    def start_output_scan(self):
        # Build the data array
        self.output_low_chan = self.get_output_low_channel_num()
        self.output_high_chan = self.get_output_high_channel_num()
        self.num_output_chans = (
            self.output_high_chan - self.output_low_chan + 1)

        if self.output_low_chan > self.output_high_chan:
            messagebox.showerror(
                "Error",
                "Low Channel Number must be greater than or equal to High "
                "Channel Number")
            self.set_output_ui_idle_state()
            return

        points_per_channel = 1000
        rate = 1000
        num_points = self.num_output_chans * points_per_channel
        scan_options = (ScanOptions.BACKGROUND |
                        ScanOptions.CONTINUOUS | ScanOptions.SCALEDATA)
        ao_range = self.ao_info.supported_ranges[0]

        self.output_memhandle = ul.scaled_win_buf_alloc(num_points)

        # Check if the buffer was successfully allocated
        if not self.output_memhandle:
            messagebox.showerror("Error", "Failed to allocate memory")
            self.output_start_button["state"] = tk.NORMAL
            return

        try:
            data_array = cast(self.output_memhandle, POINTER(c_double))
            frequencies = self.add_output_example_data(
                data_array, ao_range, self.num_output_chans, rate,
                points_per_channel)

            self.recreate_freq_frame()
            self.display_output_signal_info(frequencies)

            ul.a_out_scan(
                self.board_num, self.output_low_chan, self.output_high_chan,
                num_points, rate, ao_range, self.output_memhandle,
                scan_options)

            # Start updating the displayed values
            self.update_output_displayed_values()
        except ULError as e:
            show_ul_error(e)
            self.set_output_ui_idle_state()
            return

    def display_output_signal_info(self, frequencies):
        for channel_num in range(
                self.output_low_chan, self.output_high_chan + 1):
            curr_row = channel_num - self.output_low_chan
            self.freq_labels[curr_row]["text"] = str(
                frequencies[curr_row]) + " Hz"

    def add_output_example_data(self, data_array, ao_range, num_chans,
                                rate, points_per_channel):
        # Calculate frequencies that will work well with the size of the array
        frequencies = []
        for channel_num in range(0, num_chans):
            frequencies.append(
                (channel_num + 1) / (points_per_channel / rate))

        # Calculate an amplitude and y-offset for the signal
        # to fill the analog output range
        amplitude = (ao_range.range_max - ao_range.range_min) / 2
        y_offset = (amplitude + ao_range.range_min) / 2

        # Fill the array with sine wave data at the calculated frequencies.
        # Note that since we are using the SCALEDATA option, the values
        # added to data_array are the actual voltage values that the device
        # will output
        data_index = 0
        for point_num in range(0, points_per_channel):
            for channel_num in range(0, num_chans):
                freq = frequencies[channel_num]
                value = amplitude * math.sin(
                    2 * math.pi * freq * point_num / rate) + y_offset
                data_array[data_index] = value
                data_index += 1

        return frequencies

    def update_output_displayed_values(self):
        # Get the status from the device
        status, curr_count, curr_index = ul.get_status(self.board_num,
                                                       FunctionType.AOFUNCTION)

        # Display the status info
        self.update_output_status_labels(status, curr_count, curr_index)

        # Call this method again until the stop button is pressed
        if status == Status.RUNNING:
            self.after(100, self.update_output_displayed_values)
        else:
            # Free the allocated memory
            ul.win_buf_free(self.output_memhandle)
            self.set_output_ui_idle_state()

    def update_output_status_labels(self, status, curr_count, curr_index):
        if status == Status.IDLE:
            self.output_status_label["text"] = "Idle"
        else:
            self.output_status_label["text"] = "Running"

        self.output_index_label["text"] = str(curr_index)
        self.output_count_label["text"] = str(curr_count)

    def recreate_freq_frame(self):
        low_chan = self.output_low_chan
        high_chan = self.output_high_chan

        new_freq_frame = tk.Frame(self.freq_inner_frame)

        curr_row = 0
        self.freq_labels = []
        for chan_num in range(low_chan, high_chan + 1):
            curr_row += 1
            channel_label = tk.Label(new_freq_frame)
            channel_label["text"] = (
                "Channel " + str(chan_num) + " Frequency:")
            channel_label.grid(row=curr_row, column=0, sticky=tk.W)

            freq_label = tk.Label(new_freq_frame)
            freq_label.grid(row=curr_row, column=1, sticky=tk.W)
            self.freq_labels.append(freq_label)

        self.freq_frame.destroy()
        self.freq_frame = new_freq_frame
        self.freq_frame.grid()

    def stop_output(self):
        ul.stop_background(self.board_num, FunctionType.AOFUNCTION)

    def set_output_ui_idle_state(self):
        self.output_high_channel_entry["state"] = tk.NORMAL
        self.output_low_channel_entry["state"] = tk.NORMAL
        self.output_start_button["command"] = self.start_output
        self.output_start_button["text"] = "Start Analog Output"

    def start_output(self):
        self.output_high_channel_entry["state"] = tk.DISABLED
        self.output_low_channel_entry["state"] = tk.DISABLED
        self.output_start_button["command"] = self.stop_output
        self.output_start_button["text"] = "Stop Analog Output"
        self.start_output_scan()

    def stop_input(self):
        ul.stop_background(self.board_num, FunctionType.AIFUNCTION)

    def set_input_ui_idle_state(self):
        self.input_high_channel_entry["state"] = tk.NORMAL
        self.input_low_channel_entry["state"] = tk.NORMAL
        self.input_start_button["command"] = self.start_input
        self.input_start_button["text"] = "Start Analog Input"

    def start_input(self):
        self.input_high_channel_entry["state"] = tk.DISABLED
        self.input_low_channel_entry["state"] = tk.DISABLED
        self.input_start_button["command"] = self.stop_input
        self.input_start_button["text"] = "Stop Analog Input"
        self.start_input_scan()

    def get_input_low_channel_num(self):
        if self.ai_info.num_chans == 1:
            return 0
        try:
            return int(self.input_low_channel_entry.get())
        except ValueError:
            return 0

    def get_input_high_channel_num(self):
        if self.ai_info.num_chans == 1:
            return 0
        try:
            return int(self.input_high_channel_entry.get())
        except ValueError:
            return 0

    def get_output_low_channel_num(self):
        if self.ao_info.num_chans == 1:
            return 0
        try:
            return int(self.output_low_channel_entry.get())
        except ValueError:
            return 0

    def get_output_high_channel_num(self):
        if self.ao_info.num_chans == 1:
            return 0
        try:
            return int(self.output_high_channel_entry.get())
        except ValueError:
            return 0

    def validate_channel_entry(self, p):
        if p == '':
            return True
        try:
            value = int(p)
            if value < 0 or value > self.ai_info.num_chans - 1:
                return False
        except ValueError:
            return False

        return True

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num)
                                     + ": " + self.device_info.product_name
                                     + " (" + self.device_info.unique_id + ")")

        channel_vcmd = self.register(self.validate_channel_entry)

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)

        input_groupbox = tk.LabelFrame(main_frame, text="Analog Input")
        input_groupbox.pack(side=tk.LEFT, anchor=tk.NW)

        if self.ai_info.num_chans > 1:
            curr_row = 0

            input_channels_frame = tk.Frame(input_groupbox)
            input_channels_frame.pack(fill=tk.X, anchor=tk.NW)

            input_low_channel_entry_label = tk.Label(
                input_channels_frame)
            input_low_channel_entry_label["text"] = (
                "Low Channel Number:")
            input_low_channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.input_low_channel_entry = tk.Spinbox(
                input_channels_frame, from_=0,
                to=max(self.ai_info.num_chans - 1, 0),
                validate='key', validatecommand=(channel_vcmd, '%P'))
            self.input_low_channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)

            curr_row += 1
            input_high_channel_entry_label = tk.Label(
                input_channels_frame)
            input_high_channel_entry_label["text"] = (
                "High Channel Number:")
            input_high_channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.input_high_channel_entry = tk.Spinbox(
                input_channels_frame, from_=0,
                to=max(self.ai_info.num_chans - 1, 0),
                validate='key', validatecommand=(channel_vcmd, '%P'))
            self.input_high_channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)
            initial_value = min(self.ai_info.num_chans - 1, 3)
            self.input_high_channel_entry.delete(0, tk.END)
            self.input_high_channel_entry.insert(0, str(initial_value))

            curr_row += 1

        self.input_start_button = tk.Button(input_groupbox)
        self.input_start_button["text"] = "Start Analog Input"
        self.input_start_button["command"] = self.start_input
        self.input_start_button.pack(
            fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.input_results_group = tk.LabelFrame(
            input_groupbox, text="Results", padx=3, pady=3)
        self.input_results_group.pack(
            fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.input_results_group.grid_columnconfigure(1, weight=1)

        curr_row = 0
        input_status_left_label = tk.Label(self.input_results_group)
        input_status_left_label["text"] = "Status:"
        input_status_left_label.grid(
            row=curr_row, column=0, sticky=tk.W)

        self.input_status_label = tk.Label(self.input_results_group)
        self.input_status_label["text"] = "Idle"
        self.input_status_label.grid(
            row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        input_index_left_label = tk.Label(self.input_results_group)
        input_index_left_label["text"] = "Index:"
        input_index_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.input_index_label = tk.Label(self.input_results_group)
        self.input_index_label["text"] = "-1"
        self.input_index_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        input_count_left_label = tk.Label(self.input_results_group)
        input_count_left_label["text"] = "Count:"
        input_count_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.input_count_label = tk.Label(self.input_results_group)
        self.input_count_label["text"] = "0"
        self.input_count_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        self.input_inner_data_frame = tk.Frame(self.input_results_group)
        self.input_inner_data_frame.grid(
            row=curr_row, column=0, columnspan=2, sticky=tk.W)

        self.data_frame = tk.Frame(self.input_inner_data_frame)
        self.data_frame.grid()

        output_groupbox = tk.LabelFrame(
            main_frame, text="Analog Output")
        output_groupbox.pack(side=tk.RIGHT, anchor=tk.NW)

        if self.ao_info.num_chans > 1:
            curr_row = 0
            output_channels_frame = tk.Frame(output_groupbox)
            output_channels_frame.pack(fill=tk.X, anchor=tk.NW)

            output_low_channel_entry_label = tk.Label(
                output_channels_frame)
            output_low_channel_entry_label["text"] = (
                "Low Channel Number:")
            output_low_channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.output_low_channel_entry = tk.Spinbox(
                output_channels_frame, from_=0,
                to=max(self.ao_info.num_chans - 1, 0),
                validate='key', validatecommand=(channel_vcmd, '%P'))
            self.output_low_channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)

            curr_row += 1
            output_high_channel_entry_label = tk.Label(
                output_channels_frame)
            output_high_channel_entry_label["text"] = (
                "High Channel Number:")
            output_high_channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.output_high_channel_entry = tk.Spinbox(
                output_channels_frame, from_=0,
                to=max(self.ao_info.num_chans - 1, 0),
                validate='key', validatecommand=(channel_vcmd, '%P'))
            self.output_high_channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)
            initial_value = min(self.ao_info.num_chans - 1, 3)
            self.output_high_channel_entry.delete(0, tk.END)
            self.output_high_channel_entry.insert(0, str(initial_value))

        self.output_start_button = tk.Button(output_groupbox)
        self.output_start_button["text"] = "Start Analog Output"
        self.output_start_button["command"] = self.start_output
        self.output_start_button.pack(
            fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        output_scan_info_group = tk.LabelFrame(
            output_groupbox, text="Scan Information", padx=3, pady=3)
        output_scan_info_group.pack(
            fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        output_scan_info_group.grid_columnconfigure(1, weight=1)

        curr_row = 0
        output_status_left_label = tk.Label(output_scan_info_group)
        output_status_left_label["text"] = "Status:"
        output_status_left_label.grid(
            row=curr_row, column=0, sticky=tk.W)

        self.output_status_label = tk.Label(output_scan_info_group)
        self.output_status_label["text"] = "Idle"
        self.output_status_label.grid(
            row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        output_index_left_label = tk.Label(output_scan_info_group)
        output_index_left_label["text"] = "Index:"
        output_index_left_label.grid(
            row=curr_row, column=0, sticky=tk.W)

        self.output_index_label = tk.Label(output_scan_info_group)
        self.output_index_label["text"] = "-1"
        self.output_index_label.grid(
            row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        output_count_left_label = tk.Label(output_scan_info_group)
        output_count_left_label["text"] = "Count:"
        output_count_left_label.grid(
            row=curr_row, column=0, sticky=tk.W)

        self.output_count_label = tk.Label(output_scan_info_group)
        self.output_count_label["text"] = "0"
        self.output_count_label.grid(
            row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        self.freq_inner_frame = tk.Frame(output_scan_info_group)
        self.freq_inner_frame.grid(
            row=curr_row, column=0, columnspan=2, sticky=tk.W)

        self.freq_frame = tk.Frame(self.freq_inner_frame)
        self.freq_frame.grid()

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.quit_button = tk.Button(button_frame)
        self.quit_button["text"] = "Quit"
        self.quit_button["command"] = self.exit
        self.quit_button.grid(row=0, column=1, padx=3, pady=3)
Example #7
0
class ULAI01(UIExample):
    def __init__(self, master):
        super(ULAI01, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        use_device_detection = True
        self.board_num = 0

        self.running = False

        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            if self.device_info.supports_analog_input:
                self.ai_info = self.device_info.get_ai_info()
                self.create_widgets()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets(True)

    def update_value(self):
        channel = self.get_channel_num()
        ai_range = self.ai_info.supported_ranges[0]

        try:
            # Get a value from the device
            if self.ai_info.resolution <= 16:
                # Use the a_in method for devices with a resolution <= 16
                value = ul.a_in(self.board_num, channel, ai_range)
                # Convert the raw value to engineering units
                eng_units_value = ul.to_eng_units(self.board_num, ai_range,
                                                  value)
            else:
                # Use the a_in_32 method for devices with a resolution > 16
                # (optional parameter omitted)
                value = ul.a_in_32(self.board_num, channel, ai_range)
                # Convert the raw value to engineering units
                eng_units_value = ul.to_eng_units_32(self.board_num, ai_range,
                                                     value)

            # Display the raw value
            self.value_label["text"] = str(value)
            # Display the engineering value
            self.eng_value_label["text"] = '{:.3f}'.format(eng_units_value)

            # Call this method again until the stop button is pressed (or an
            # error occurs)
            if self.running:
                self.after(100, self.update_value)
        except ULError as e:
            self.stop()
            show_ul_error(e)

    def stop(self):
        self.running = False
        self.start_button["command"] = self.start
        self.start_button["text"] = "Start"

    def start(self):
        self.running = True
        self.start_button["command"] = self.stop
        self.start_button["text"] = "Stop"
        self.update_value()

    def get_channel_num(self):
        if self.ai_info.num_chans == 1:
            return 0
        try:
            return int(self.channel_entry.get())
        except ValueError:
            return 0

    def validate_channel_entry(self, p):
        if p == '':
            return True
        try:
            value = int(p)
            if value < 0 or value > self.ai_info.num_chans - 1:
                return False
        except ValueError:
            return False

        return True

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num)
                                     + ": " + self.device_info.product_name
                                     + " (" + self.device_info.unique_id + ")")

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)

        curr_row = 0
        if self.ai_info.num_chans > 1:
            channel_vcmd = self.register(self.validate_channel_entry)

            channel_entry_label = tk.Label(main_frame)
            channel_entry_label["text"] = "Channel Number:"
            channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.channel_entry = tk.Spinbox(
                main_frame, from_=0,
                to=max(self.ai_info.num_chans - 1, 0),
                validate='key', validatecommand=(channel_vcmd, '%P'))
            self.channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)

            curr_row += 1

        raw_value_left_label = tk.Label(main_frame)
        raw_value_left_label["text"] = "Value read from selected channel:"
        raw_value_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.value_label = tk.Label(main_frame)
        self.value_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        eng_value_left_label = tk.Label(main_frame)
        eng_value_left_label["text"] = "Value converted to voltage:"
        eng_value_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.eng_value_label = tk.Label(main_frame)
        self.eng_value_label.grid(row=curr_row, column=1, sticky=tk.W)

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.start_button = tk.Button(button_frame)
        self.start_button["text"] = "Start"
        self.start_button["command"] = self.start
        self.start_button.grid(row=0, column=0, padx=3, pady=3)

        quit_button = tk.Button(button_frame)
        quit_button["text"] = "Quit"
        quit_button["command"] = self.master.destroy
        quit_button.grid(row=0, column=1, padx=3, pady=3)
Example #8
0
def run_example():
    # By default, the example detects and displays all available devices and
    # selects the first device listed. Use the dev_id_list variable to filter
    # detected devices by device ID (see UL documentation for device IDs).
    # If use_device_detection is set to False, the board_num variable needs to
    # match the desired board number configured with Instacal.
    use_device_detection = True
    dev_id_list = []
    board_num = 0
    rate = 100
    file_name = 'scan_data.csv'
    memhandle = None

    # The size of the UL buffer to create, in seconds
    buffer_size_seconds = 2
    # The number of buffers to write. After this number of UL buffers are
    # written to file, the example will be stopped.
    num_buffers_to_write = 5

    try:
        if use_device_detection:
            config_first_detected_device(board_num, dev_id_list)

        daq_dev_info = DaqDeviceInfo(board_num)
        if not daq_dev_info.supports_analog_input:
            raise Exception('Error: The DAQ device does not support '
                            'analog input')

        print('\nActive DAQ device: ', daq_dev_info.product_name, ' (',
              daq_dev_info.unique_id, ')\n', sep='')

        ai_info = daq_dev_info.get_ai_info()

        low_chan = 0
        high_chan = min(3, ai_info.num_chans - 1)
        num_chans = high_chan - low_chan + 1

        # Create a circular buffer that can hold buffer_size_seconds worth of
        # data, or at least 10 points (this may need to be adjusted to prevent
        # a buffer overrun)
        points_per_channel = max(rate * buffer_size_seconds, 10)

        # Some hardware requires that the total_count is an integer multiple
        # of the packet size. For this case, calculate a points_per_channel
        # that is equal to or just above the points_per_channel selected
        # which matches that requirement.
        if ai_info.packet_size != 1:
            packet_size = ai_info.packet_size
            remainder = points_per_channel % packet_size
            if remainder != 0:
                points_per_channel += packet_size - remainder

        ul_buffer_count = points_per_channel * num_chans

        # Write the UL buffer to the file num_buffers_to_write times.
        points_to_write = ul_buffer_count * num_buffers_to_write

        # When handling the buffer, we will read 1/10 of the buffer at a time
        write_chunk_size = int(ul_buffer_count / 10)

        ai_range = ai_info.supported_ranges[0]

        scan_options = (ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS |
                        ScanOptions.SCALEDATA)

        memhandle = ul.scaled_win_buf_alloc(ul_buffer_count)

        # Allocate an array of doubles temporary storage of the data
        write_chunk_array = (c_double * write_chunk_size)()

        # Check if the buffer was successfully allocated
        if not memhandle:
            raise Exception('Failed to allocate memory')

        # Start the scan
        ul.a_in_scan(
            board_num, low_chan, high_chan, ul_buffer_count,
            rate, ai_range, memhandle, scan_options)

        status = Status.IDLE
        # Wait for the scan to start fully
        while status == Status.IDLE:
            status, _, _ = ul.get_status(board_num, FunctionType.AIFUNCTION)

        # Create a file for storing the data
        with open(file_name, 'w') as f:
            print('Writing data to ' + file_name, end='')

            # Write a header to the file
            for chan_num in range(low_chan, high_chan + 1):
                f.write('Channel ' + str(chan_num) + ',')
            f.write(u'\n')

            # Start the write loop
            prev_count = 0
            prev_index = 0
            write_ch_num = low_chan
            while status != Status.IDLE:
                # Get the latest counts
                status, curr_count, _ = ul.get_status(board_num,
                                                      FunctionType.AIFUNCTION)

                new_data_count = curr_count - prev_count

                # Check for a buffer overrun before copying the data, so
                # that no attempts are made to copy more than a full buffer
                # of data
                if new_data_count > ul_buffer_count:
                    # Print an error and stop writing
                    ul.stop_background(board_num, FunctionType.AIFUNCTION)
                    print('A buffer overrun occurred')
                    break

                # Check if a chunk is available
                if new_data_count > write_chunk_size:
                    wrote_chunk = True
                    # Copy the current data to a new array

                    # Check if the data wraps around the end of the UL
                    # buffer. Multiple copy operations will be required.
                    if prev_index + write_chunk_size > ul_buffer_count - 1:
                        first_chunk_size = ul_buffer_count - prev_index
                        second_chunk_size = (
                            write_chunk_size - first_chunk_size)

                        # Copy the first chunk of data to the
                        # write_chunk_array
                        ul.scaled_win_buf_to_array(
                            memhandle, write_chunk_array, prev_index,
                            first_chunk_size)

                        # Create a pointer to the location in
                        # write_chunk_array where we want to copy the
                        # remaining data
                        second_chunk_pointer = cast(addressof(write_chunk_array)
                                                    + first_chunk_size
                                                    * sizeof(c_double),
                                                    POINTER(c_double))

                        # Copy the second chunk of data to the
                        # write_chunk_array
                        ul.scaled_win_buf_to_array(
                            memhandle, second_chunk_pointer,
                            0, second_chunk_size)
                    else:
                        # Copy the data to the write_chunk_array
                        ul.scaled_win_buf_to_array(
                            memhandle, write_chunk_array, prev_index,
                            write_chunk_size)

                    # Check for a buffer overrun just after copying the data
                    # from the UL buffer. This will ensure that the data was
                    # not overwritten in the UL buffer before the copy was
                    # completed. This should be done before writing to the
                    # file, so that corrupt data does not end up in it.
                    status, curr_count, _ = ul.get_status(
                        board_num, FunctionType.AIFUNCTION)
                    if curr_count - prev_count > ul_buffer_count:
                        # Print an error and stop writing
                        ul.stop_background(board_num, FunctionType.AIFUNCTION)
                        print('A buffer overrun occurred')
                        break

                    for i in range(write_chunk_size):
                        f.write(str(write_chunk_array[i]) + ',')
                        write_ch_num += 1
                        if write_ch_num == high_chan + 1:
                            write_ch_num = low_chan
                            f.write(u'\n')
                else:
                    wrote_chunk = False

                if wrote_chunk:
                    # Increment prev_count by the chunk size
                    prev_count += write_chunk_size
                    # Increment prev_index by the chunk size
                    prev_index += write_chunk_size
                    # Wrap prev_index to the size of the UL buffer
                    prev_index %= ul_buffer_count

                    if prev_count >= points_to_write:
                        break
                    print('.', end='')
                else:
                    # Wait a short amount of time for more data to be
                    # acquired.
                    sleep(0.1)

        ul.stop_background(board_num, FunctionType.AIFUNCTION)
    except Exception as e:
        print('\n', e)
    finally:
        print('Done')
        if memhandle:
            # Free the buffer in a finally block to prevent  a memory leak.
            ul.win_buf_free(memhandle)
        if use_device_detection:
            ul.release_daq_device(board_num)
Example #9
0
class ULTI02(UIExample):
    def __init__(self, master):
        super(ULTI02, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        use_device_detection = True
        self.board_num = 0

        self.running = False

        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            self.ai_info = self.device_info.get_ai_info()
            if self.ai_info.temp_supported:
                self.create_widgets()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets(True)

    def update_values(self):
        try:
            # Get the values from the device (optional parameters omitted)
            err_code, data_array = ul.t_in_scan(self.board_num, self.low_chan,
                                                self.high_chan,
                                                TempScale.CELSIUS)

            # Check err_code for OUTOFRANGE or OPENCONNECTION. All other
            # error codes will raise a ULError and are checked by the except
            # clause.
            if err_code == ErrorCode.OUTOFRANGE:
                self.warning_label["text"] = (
                    "A thermocouple input is out of range.")
            elif err_code == ErrorCode.OPENCONNECTION:
                self.warning_label["text"] = (
                    "A thermocouple input has an open connection.")
            else:
                self.warning_label["text"] = ""

            self.display_values(data_array)

            # Call this method again until the stop button is pressed (or an
            # error occurs)
            if self.running:
                self.after(100, self.update_values)
        except ULError as e:
            self.stop()
            show_ul_error(e)

    def display_values(self, array):
        low_chan = self.low_chan
        high_chan = self.high_chan

        for chan_num in range(low_chan, high_chan + 1):
            index = chan_num - low_chan
            self.data_labels[index]["text"] = '{:.3f}'.format(
                array[index]) + "\n"

    def stop(self):
        self.running = False
        self.start_button["command"] = self.start
        self.start_button["text"] = "Start"
        self.low_channel_entry["state"] = tk.NORMAL
        self.high_channel_entry["state"] = tk.NORMAL

    def start(self):
        self.running = True
        self.start_button["command"] = self.stop
        self.start_button["text"] = "Stop"
        self.low_channel_entry["state"] = tk.DISABLED
        self.high_channel_entry["state"] = tk.DISABLED
        self.low_chan = self.get_low_channel_num()
        self.high_chan = self.get_high_channel_num()
        self.recreate_data_frame()
        self.update_values()

    def get_low_channel_num(self):
        try:
            return int(self.low_channel_entry.get())
        except ValueError:
            return 0

    def get_high_channel_num(self):
        try:
            return int(self.high_channel_entry.get())
        except ValueError:
            return 0

    def validate_channel_entry(self, p):
        if p == '':
            return True
        try:
            value = int(p)
            if value < 0 or value > self.ai_info.num_temp_chans - 1:
                return False
        except ValueError:
            return False

        return True

    def recreate_data_frame(self):
        low_chan = self.low_chan
        high_chan = self.high_chan
        channels_per_row = 4

        new_data_frame = tk.Frame(self.results_group)

        self.data_labels = []
        row = 0
        column = 0
        # Add the labels for each channel
        for chan_num in range(low_chan, high_chan + 1):
            chan_label = tk.Label(new_data_frame, justify=tk.LEFT, padx=3)
            chan_label["text"] = "Channel " + str(chan_num)
            chan_label.grid(row=row, column=column)

            data_label = tk.Label(new_data_frame, justify=tk.LEFT, padx=3)
            data_label.grid(row=row + 1, column=column)
            self.data_labels.append(data_label)

            column += 1
            if column >= channels_per_row:
                row += 2
                column = 0

        self.data_frame.destroy()
        self.data_frame = new_data_frame
        self.data_frame.pack(side=tk.TOP)

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num) +
                                     ": " + self.device_info.product_name +
                                     " (" + self.device_info.unique_id + ")")

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)
        channel_vcmd = self.register(self.validate_channel_entry)

        curr_row = 0

        if self.ai_info.num_temp_chans > 1:
            low_channel_entry_label = tk.Label(main_frame)
            low_channel_entry_label["text"] = "Low Channel Number:"
            low_channel_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.low_channel_entry = tk.Spinbox(
                main_frame,
                from_=0,
                to=max(self.ai_info.num_temp_chans - 1, 0),
                validate='key',
                validatecommand=(channel_vcmd, '%P'))
            self.low_channel_entry.grid(row=curr_row, column=1, sticky=tk.W)

            curr_row += 1
            high_channel_entry_label = tk.Label(main_frame)
            high_channel_entry_label["text"] = "High Channel Number:"
            high_channel_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

            self.high_channel_entry = tk.Spinbox(
                main_frame,
                from_=0,
                to=max(self.ai_info.num_temp_chans - 1, 0),
                validate='key',
                validatecommand=(channel_vcmd, '%P'))
            self.high_channel_entry.grid(row=curr_row, column=1, sticky=tk.W)
            initial_value = min(self.ai_info.num_temp_chans - 1, 3)
            self.high_channel_entry.delete(0, tk.END)
            self.high_channel_entry.insert(0, str(initial_value))

        self.results_group = tk.LabelFrame(self, text="Results")
        self.results_group.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.data_frame = tk.Frame(self.results_group)
        self.data_frame.pack(side=tk.TOP)

        self.warning_label = tk.Label(self.results_group, fg="red")
        self.warning_label.pack(side=tk.BOTTOM)

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.start_button = tk.Button(button_frame)
        self.start_button["text"] = "Start"
        self.start_button["command"] = self.start
        self.start_button.grid(row=0, column=0, padx=3, pady=3)

        quit_button = tk.Button(button_frame)
        quit_button["text"] = "Quit"
        quit_button["command"] = self.master.destroy
        quit_button.grid(row=0, column=1, padx=3, pady=3)
Example #10
0
class DaqInScan02(UIExample):
    def __init__(self, master=None):
        super(DaqInScan02, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        use_device_detection = True
        self.board_num = 0

        self.chan_list = []
        self.chan_type_list = []
        self.gain_list = []
        self.num_chans = 0
        self.resolution = 16

        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            if self.device_info.supports_daq_input:
                self.init_scan_channel_info()
                self.create_widgets()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets(True)

    def init_scan_channel_info(self):
        num_channels = 0

        daqi_info = self.device_info.get_daqi_info()
        supported_channel_types = daqi_info.supported_channel_types

        # Add analog input channels if available
        if ChannelType.ANALOG in supported_channel_types:
            ai_info = self.device_info.get_ai_info()
            self.resolution = ai_info.resolution
            self.chan_list.append(0)
            self.chan_type_list.append(ChannelType.ANALOG)
            self.gain_list.append(ai_info.supported_ranges[0])
            num_channels += 1

            if ai_info.num_chans > 1:
                self.chan_list.append(ai_info.num_chans - 1)
                self.chan_type_list.append(ChannelType.ANALOG)
                self.gain_list.append(ai_info.supported_ranges[0])
                num_channels += 1

        # Add a digital input channel if available
        if self.device_info.supports_digital_io:
            chan_type = None
            if ChannelType.DIGITAL16 in supported_channel_types:
                chan_type = ChannelType.DIGITAL16
            elif ChannelType.DIGITAL8 in supported_channel_types:
                chan_type = ChannelType.DIGITAL8
            elif ChannelType.DIGITAL in supported_channel_types:
                chan_type = ChannelType.DIGITAL

            if chan_type is not None:
                dio_info = self.device_info.get_dio_info()
                port_info = dio_info.port_info[0]
                self.chan_list.append(port_info.type)
                self.chan_type_list.append(chan_type)
                self.gain_list.append(ULRange.NOTUSED)
                num_channels += 1

                # Configure all digital ports for input
                for port in dio_info.port_info:
                    if port.is_port_configurable:
                        ul.d_config_port(self.board_num, port.type,
                                         DigitalIODirection.IN)

        if self.device_info.supports_counters:
            chan_type = None
            if ChannelType.CTR16 in supported_channel_types:
                chan_type = ChannelType.CTR16
            elif ChannelType.CTRBANK0 in supported_channel_types:
                chan_type = ChannelType.CTRBANK0
            elif ChannelType.CTR in supported_channel_types:
                chan_type = ChannelType.CTR

            if chan_type is not None:
                self.chan_list.append(0)
                self.chan_type_list.append(chan_type)
                self.gain_list.append(ULRange.NOTUSED)
                num_channels += 1

        self.num_chans = num_channels

    def start_scan(self):
        rate = 100
        points_per_channel = 100
        total_count = points_per_channel * self.num_chans
        scan_options = ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS

        # Allocate a buffer for the scan
        if self.resolution <= 16:
            self.memhandle = ul.win_buf_alloc(total_count)
        else:
            self.memhandle = ul.win_buf_alloc_32(total_count)

        # Check if the buffer was successfully allocated
        if not self.memhandle:
            messagebox.showerror("Error", "Failed to allocate memory")
            self.start_button["state"] = tk.NORMAL
            return

        try:
            # Run the scan
            ul.daq_in_scan(self.board_num, self.chan_list, self.chan_type_list,
                           self.gain_list, self.num_chans, rate, 0, total_count,
                           self.memhandle, scan_options)

            # Cast the memhandle to a ctypes pointer
            # Note: the ctypes array will only be valid until win_buf_free
            # is called.
            # A copy of the buffer can be created using win_buf_to_array
            # or win_buf_to_array_32 before the memory is freed. The copy can
            # be used at any time.
            if self.resolution <= 16:
                # Use the memhandle_as_ctypes_array method for devices with a
                # resolution <= 16
                self.array = cast(self.memhandle, POINTER(c_ushort))
            else:
                # Use the memhandle_as_ctypes_array_32 method for devices with a
                # resolution > 16
                self.array = cast(self.memhandle, POINTER(c_ulong))
        except ULError as e:
            # Free the allocated memory
            ul.win_buf_free(self.memhandle)
            show_ul_error(e)
            return

        # Start updating the displayed values
        self.update_displayed_values()

    def update_displayed_values(self):
        # Get the status from the device
        status, curr_count, curr_index = ul.get_status(
            self.board_num, FunctionType.DAQIFUNCTION)

        # Display the status info
        self.update_status_labels(status, curr_count, curr_index)

        # Display the values
        self.display_values(curr_index, curr_count)

        # Call this method again until the stop button is pressed
        if status == Status.RUNNING:
            self.after(100, self.update_displayed_values)
        else:
            # Free the allocated memory
            ul.win_buf_free(self.memhandle)
            self.set_ui_idle_state()

    def update_status_labels(self, status, curr_count, curr_index):
        if status == Status.IDLE:
            self.status_label["text"] = "Idle"
        else:
            self.status_label["text"] = "Running"

        self.index_label["text"] = str(curr_index)
        self.count_label["text"] = str(curr_count)

    def display_values(self, curr_index, curr_count):
        per_channel_display_count = 10
        array = self.array
        chan_count = self.num_chans
        channel_text = []

        # Add a string to the array for each channel
        for _ in range(0, self.num_chans):
            channel_text.append("")

        # If no data has been gathered, don't add data to the labels
        if curr_count > 1:
            # curr_index points to the start of the last completed channel scan
            # that was transferred between the board and the data buffer. Based
            # on this, calculate the first index we want to display using
            # subtraction.
            first_index = max(
                curr_index - ((per_channel_display_count - 1) * chan_count), 0)
            chan_num = 0
            # Add (up to) the latest 10 values for each channel to the text
            for data_index in range(
                    first_index,
                    first_index + min(chan_count * per_channel_display_count,
                                      curr_count)):
                channel_text[chan_num] += str(array[data_index]) + "\n"
                if chan_num == self.num_chans - 1:
                    chan_num = 0
                else:
                    chan_num += 1

            # Update the labels for each channel
            for chan_num in range(0, self.num_chans):
                self.data_labels[chan_num]["text"] = channel_text[chan_num]

    def stop(self):
        ul.stop_background(self.board_num, FunctionType.DAQIFUNCTION)

    def set_ui_idle_state(self):
        self.start_button["command"] = self.start
        self.start_button["text"] = "Start"

    def start(self):
        self.start_button["command"] = self.stop
        self.start_button["text"] = "Stop"
        self.start_scan()

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num)
                                     + ": " + self.device_info.product_name
                                     + " (" + self.device_info.unique_id + ")")

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)

        self.results_group = tk.LabelFrame(
            self, text="Results", padx=3, pady=3)
        self.results_group.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        curr_row = 0
        status_left_label = tk.Label(self.results_group)
        status_left_label["text"] = "Status:"
        status_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.status_label = tk.Label(self.results_group)
        self.status_label["text"] = "Idle"
        self.status_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        index_left_label = tk.Label(self.results_group)
        index_left_label["text"] = "Index:"
        index_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.index_label = tk.Label(self.results_group)
        self.index_label["text"] = "-1"
        self.index_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        count_left_label = tk.Label(self.results_group)
        count_left_label["text"] = "Count:"
        count_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.count_label = tk.Label(self.results_group)
        self.count_label["text"] = "0"
        self.count_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        self.data_frame = tk.Frame(self.results_group)
        self.data_frame.grid(row=curr_row, column=0,
                             columnspan=2, sticky=tk.W)

        chan_header_label = tk.Label(
            self.data_frame, justify=tk.LEFT, padx=3)
        chan_header_label["text"] = "Channel:"
        chan_header_label.grid(row=0, column=0)

        type_header_label = tk.Label(
            self.data_frame, justify=tk.LEFT, padx=3)
        type_header_label["text"] = "Type:"
        type_header_label.grid(row=1, column=0)

        range_header_label = tk.Label(
            self.data_frame, justify=tk.LEFT, padx=3)
        range_header_label["text"] = "Range:"
        range_header_label.grid(row=2, column=0)

        self.data_labels = []
        for chan_num in range(0, self.num_chans):
            column = chan_num + 1
            chan_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
            chan_num_item = self.chan_list[chan_num]
            if isinstance(chan_num_item, Enum):
                chan_label["text"] = self.chan_list[chan_num].name
            else:
                chan_label["text"] = str(self.chan_list[chan_num])
            chan_label.grid(row=0, column=column)

            type_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
            type_label["text"] = self.chan_type_list[chan_num].name
            type_label.grid(row=1, column=column)

            range_label = tk.Label(
                self.data_frame, justify=tk.LEFT, padx=3)
            range_label["text"] = self.gain_list[chan_num].name
            range_label.grid(row=2, column=column)

            data_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
            data_label.grid(row=3, column=column)
            self.data_labels.append(data_label)

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.start_button = tk.Button(button_frame)
        self.start_button["text"] = "Start"
        self.start_button["command"] = self.start
        self.start_button.grid(row=0, column=0, padx=3, pady=3)

        quit_button = tk.Button(button_frame)
        quit_button["text"] = "Quit"
        quit_button["command"] = self.master.destroy
        quit_button.grid(row=0, column=1, padx=3, pady=3)
Example #11
0
def run_example():
    # By default, the example detects and displays all available devices and
    # selects the first device listed. Use the dev_id_list variable to filter
    # detected devices by device ID (see UL documentation for device IDs).
    # If use_device_detection is set to False, the board_num variable needs to
    # match the desired board number configured with Instacal.
    use_device_detection = True
    dev_id_list = []
    board_num = 0
    rate = 100
    points_per_channel = 10
    memhandle = None

    try:
        if use_device_detection:
            config_first_detected_device(board_num, dev_id_list)

        daq_dev_info = DaqDeviceInfo(board_num)
        if not daq_dev_info.supports_analog_input:
            raise Exception('Error: The DAQ device does not support '
                            'analog input')

        print('\nActive DAQ device: ',
              daq_dev_info.product_name,
              ' (',
              daq_dev_info.unique_id,
              ')\n',
              sep='')

        ai_info = daq_dev_info.get_ai_info()

        low_chan = 0
        high_chan = min(3, ai_info.num_chans - 1)
        num_chans = high_chan - low_chan + 1

        total_count = points_per_channel * num_chans

        ai_range = ai_info.supported_ranges[0]

        scan_options = ScanOptions.FOREGROUND

        if ScanOptions.SCALEDATA in ai_info.supported_scan_options:
            # If the hardware supports the SCALEDATA option, it is easiest to
            # use it.
            scan_options |= ScanOptions.SCALEDATA

            memhandle = ul.scaled_win_buf_alloc(total_count)
            # Convert the memhandle to a ctypes array.
            # Use the memhandle_as_ctypes_array_scaled method for scaled
            # buffers.
            ctypes_array = cast(memhandle, POINTER(c_double))
        elif ai_info.resolution <= 16:
            # Use the win_buf_alloc method for devices with a resolution <= 16
            memhandle = ul.win_buf_alloc(total_count)
            # Convert the memhandle to a ctypes array.
            # Use the memhandle_as_ctypes_array method for devices with a
            # resolution <= 16.
            ctypes_array = cast(memhandle, POINTER(c_ushort))
        else:
            # Use the win_buf_alloc_32 method for devices with a resolution > 16
            memhandle = ul.win_buf_alloc_32(total_count)
            # Convert the memhandle to a ctypes array.
            # Use the memhandle_as_ctypes_array_32 method for devices with a
            # resolution > 16
            ctypes_array = cast(memhandle, POINTER(c_ulong))

        # Note: the ctypes array will no longer be valid after win_buf_free is
        # called.
        # A copy of the buffer can be created using win_buf_to_array or
        # win_buf_to_array_32 before the memory is freed. The copy can be used
        # at any time.

        # Check if the buffer was successfully allocated
        if not memhandle:
            raise Exception('Error: Failed to allocate memory')

        # Start the scan
        ul.a_in_scan(board_num, low_chan, high_chan, total_count, rate,
                     ai_range, memhandle, scan_options)

        print('Scan completed successfully. Data:')

        # Create a format string that aligns the data in columns
        row_format = '{:>5}' + '{:>10}' * num_chans

        # Print the channel name headers
        labels = ['Index']
        for ch_num in range(low_chan, high_chan + 1):
            labels.append('CH' + str(ch_num))
        print(row_format.format(*labels))

        # Print the data
        data_index = 0
        for index in range(points_per_channel):
            display_data = [index]
            for _ in range(num_chans):
                if ScanOptions.SCALEDATA in scan_options:
                    # If the SCALEDATA ScanOption was used, the values
                    # in the array are already in engineering units.
                    eng_value = ctypes_array[data_index]
                else:
                    # If the SCALEDATA ScanOption was NOT used, the
                    # values in the array must be converted to
                    # engineering units using ul.to_eng_units().
                    eng_value = ul.to_eng_units(board_num, ai_range,
                                                ctypes_array[data_index])
                data_index += 1
                display_data.append('{:.3f}'.format(eng_value))
            # Print this row
            print(row_format.format(*display_data))
    except Exception as e:
        print('\n', e)
    finally:
        if memhandle:
            # Free the buffer in a finally block to prevent a memory leak.
            ul.win_buf_free(memhandle)
        if use_device_detection:
            ul.release_daq_device(board_num)
Example #12
0
class DaqInScan01(UIExample):
    def __init__(self, master=None):
        super(DaqInScan01, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        use_device_detection = True
        self.board_num = 0

        self.chan_list = []
        self.chan_type_list = []
        self.gain_list = []
        self.num_chans = 0
        self.resolution = 16

        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            if self.device_info.supports_daq_input:
                self.init_scan_channel_info()
                self.create_widgets()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets(True)

    def init_scan_channel_info(self):
        num_channels = 0

        daqi_info = self.device_info.get_daqi_info()
        supported_channel_types = daqi_info.supported_channel_types

        # Add analog input channels if available
        if ChannelType.ANALOG in supported_channel_types:
            ai_info = self.device_info.get_ai_info()
            self.resolution = ai_info.resolution
            self.chan_list.append(0)
            self.chan_type_list.append(ChannelType.ANALOG)
            self.gain_list.append(ai_info.supported_ranges[0])
            num_channels += 1

            ai_info = self.device_info.get_ai_info()
            if ai_info.num_chans > 1:
                self.chan_list.append(ai_info.num_chans - 1)
                self.chan_type_list.append(ChannelType.ANALOG)
                self.gain_list.append(ai_info.supported_ranges[0])
                num_channels += 1

        # Add a digital input channel if available
        if self.device_info.supports_digital_io:
            chan_type = None
            if ChannelType.DIGITAL16 in supported_channel_types:
                chan_type = ChannelType.DIGITAL16
            elif ChannelType.DIGITAL8 in supported_channel_types:
                chan_type = ChannelType.DIGITAL8
            elif ChannelType.DIGITAL in supported_channel_types:
                chan_type = ChannelType.DIGITAL

            if chan_type is not None:
                dio_info = self.device_info.get_dio_info()
                port_info = dio_info.port_info[0]
                self.chan_list.append(port_info.type)
                self.chan_type_list.append(chan_type)
                self.gain_list.append(ULRange.NOTUSED)
                num_channels += 1

                # Configure all digital ports for input
                for port in dio_info.port_info:
                    if port.is_port_configurable:
                        ul.d_config_port(self.board_num, port.type,
                                         DigitalIODirection.IN)

        if self.device_info.supports_counters:
            chan_type = None
            if ChannelType.CTR16 in supported_channel_types:
                chan_type = ChannelType.CTR16
            elif ChannelType.CTRBANK0 in supported_channel_types:
                chan_type = ChannelType.CTRBANK0
            elif ChannelType.CTR in supported_channel_types:
                chan_type = ChannelType.CTR

            if chan_type is not None:
                self.chan_list.append(0)
                self.chan_type_list.append(chan_type)
                self.gain_list.append(ULRange.NOTUSED)
                num_channels += 1

        self.num_chans = num_channels

    def start_scan(self):
        rate = 100
        points_per_channel = 10
        total_count = points_per_channel * self.num_chans

        # Allocate a buffer for the scan
        if self.resolution <= 16:
            memhandle = ul.win_buf_alloc(total_count)
        else:
            memhandle = ul.win_buf_alloc_32(total_count)

        # Check if the buffer was successfully allocated
        if not memhandle:
            messagebox.showerror("Error", "Failed to allocate memory")
            self.start_button["state"] = tk.NORMAL
            return

        try:
            # Run the scan
            ul.daq_in_scan(self.board_num, self.chan_list, self.chan_type_list,
                           self.gain_list, self.num_chans, rate, 0,
                           total_count, memhandle, 0)

            # Cast the memhandle to a ctypes pointer
            # Note: the ctypes array will only be valid until win_buf_free
            # is called.
            # A copy of the buffer can be created using win_buf_to_array
            # or win_buf_to_array_32 before the memory is freed. The copy can
            # be used at any time.
            if self.resolution <= 16:
                # Use the memhandle_as_ctypes_array method for devices with a
                # resolution <= 16
                array = cast(memhandle, POINTER(c_ushort))
            else:
                # Use the memhandle_as_ctypes_array_32 method for devices with
                # a resolution > 16
                array = cast(memhandle, POINTER(c_ulong))

            # Display the values
            self.display_values(array, total_count)
        except ULError as e:
            show_ul_error(e)
        finally:
            # Free the allocated memory
            ul.win_buf_free(memhandle)
            self.start_button["state"] = tk.NORMAL

    def display_values(self, array, total_count):
        channel_text = []

        # Add a string to the array for each channel
        for _ in range(0, self.num_chans):
            channel_text.append("")

        # Add (up to) the first 10 values for each channel to the text
        chan_num = 0
        for data_index in range(0, min(self.num_chans * 10, total_count)):
            channel_text[chan_num] += str(array[data_index]) + "\n"
            if chan_num == self.num_chans - 1:
                chan_num = 0
            else:
                chan_num += 1

        # Update the labels for each channel
        for chan_num in range(0, self.num_chans):
            self.data_labels[chan_num]["text"] = channel_text[chan_num]

    def start(self):
        self.start_button["state"] = tk.DISABLED
        self.start_scan()

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num) +
                                     ": " + self.device_info.product_name +
                                     " (" + self.device_info.unique_id + ")")

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)

        self.results_group = tk.LabelFrame(self,
                                           text="Results",
                                           padx=3,
                                           pady=3)
        self.results_group.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.data_frame = tk.Frame(self.results_group)
        self.data_frame.grid()

        chan_header_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
        chan_header_label["text"] = "Channel:"
        chan_header_label.grid(row=0, column=0)

        type_header_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
        type_header_label["text"] = "Type:"
        type_header_label.grid(row=1, column=0)

        range_header_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
        range_header_label["text"] = "Range:"
        range_header_label.grid(row=2, column=0)

        self.data_labels = []
        for chan_num in range(0, self.num_chans):
            column = chan_num + 1
            chan_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
            chan_num_item = self.chan_list[chan_num]
            if isinstance(chan_num_item, Enum):
                chan_label["text"] = self.chan_list[chan_num].name
            else:
                chan_label["text"] = str(self.chan_list[chan_num])
            chan_label.grid(row=0, column=column)

            type_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
            type_label["text"] = self.chan_type_list[chan_num].name
            type_label.grid(row=1, column=column)

            range_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
            range_label["text"] = self.gain_list[chan_num].name
            range_label.grid(row=2, column=column)

            data_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
            data_label.grid(row=3, column=column)
            self.data_labels.append(data_label)

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.start_button = tk.Button(button_frame)
        self.start_button["text"] = "Start"
        self.start_button["command"] = self.start
        self.start_button.grid(row=0, column=0, padx=3, pady=3)

        quit_button = tk.Button(button_frame)
        quit_button["text"] = "Quit"
        quit_button["command"] = self.master.destroy
        quit_button.grid(row=0, column=1, padx=3, pady=3)
Example #13
0
class ULAI07(UIExample):
    def __init__(self, master=None):
        super(ULAI07, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        use_device_detection = True
        self.board_num = 0

        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            self.ai_info = self.device_info.get_ai_info()
            if self.ai_info.is_supported and self.ai_info.resolution <= 16:
                self.create_widgets()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets(True)

    def update_value(self):
        channel = self.get_channel_num()
        ai_range = self.ai_info.supported_ranges[0]

        try:
            gain = self.ai_info.supported_ranges[0]
            trig_type = self.get_trigger_type()
            trig_value_eng = self.get_trigger_level()
            trig_value = ul.from_eng_units(self.board_num, gain,
                                           trig_value_eng)

            # Get a value from the device
            value = ul.a_trig(self.board_num, channel, trig_type, trig_value,
                              gain)
            # Convert the raw value to engineering units
            eng_units_value = ul.to_eng_units(self.board_num, ai_range, value)

            # Display the raw value
            self.value_label["text"] = str(value)
            # Display the engineering value
            self.eng_value_label["text"] = '{:.3f}'.format(eng_units_value)
        except ULError as e:
            self.stop()
            show_ul_error(e)

    def start(self):
        self.update_value()

    def get_channel_num(self):
        try:
            return int(self.channel_entry.get())
        except ValueError:
            return 0

    def get_trigger_type(self):
        if self.trigger_type_combobox.get() == "Above":
            return TrigType.TRIG_ABOVE
        else:
            return TrigType.TRIG_BELOW

    def get_trigger_level(self):
        try:
            return float(self.trigger_level_entry.get())
        except ValueError:
            return 0

    def validate_channel_entry(self, p):
        if p == '':
            return True
        try:
            value = int(p)
            if value < 0 or value > self.ai_info.num_chans - 1:
                return False
        except ValueError:
            return False
        return True

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num) +
                                     ": " + self.device_info.product_name +
                                     " (" + self.device_info.unique_id + ")")

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)

        channel_vcmd = self.register(self.validate_channel_entry)
        float_vcmd = self.register(validate_float_entry)

        curr_row = 0
        channel_entry_label = tk.Label(main_frame)
        channel_entry_label["text"] = "Channel Number:"
        channel_entry_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.channel_entry = tk.Spinbox(main_frame,
                                        from_=0,
                                        to=max(self.ai_info.num_chans - 1, 0),
                                        validate='key',
                                        validatecommand=(channel_vcmd, '%P'))
        self.channel_entry.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        trigger_type_label = tk.Label(main_frame)
        trigger_type_label["text"] = "Trigger Type:"
        trigger_type_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.trigger_type_combobox = Combobox(main_frame)
        self.trigger_type_combobox["values"] = ["Above", "Below"]
        self.trigger_type_combobox["state"] = "readonly"
        self.trigger_type_combobox.current(0)
        self.trigger_type_combobox.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        trigger_level_label = tk.Label(main_frame)
        trigger_level_label["text"] = "Trigger Level (V):"
        trigger_level_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.trigger_level_entry = tk.Entry(main_frame,
                                            validate='key',
                                            validatecommand=(float_vcmd, '%P'))
        self.trigger_level_entry.grid(row=curr_row, column=1, sticky=tk.W)
        self.trigger_level_entry.insert(0, "2")

        curr_row += 1
        raw_value_left_label = tk.Label(main_frame)
        raw_value_left_label["text"] = ("Value read from selected channel:")
        raw_value_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.value_label = tk.Label(main_frame)
        self.value_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        eng_value_left_label = tk.Label(main_frame)
        eng_value_left_label["text"] = "Value converted to voltage:"
        eng_value_left_label.grid(row=curr_row, column=0, sticky=tk.W)

        self.eng_value_label = tk.Label(main_frame)
        self.eng_value_label.grid(row=curr_row, column=1, sticky=tk.W)

        curr_row += 1
        warning_label = tk.Label(main_frame,
                                 justify=tk.LEFT,
                                 wraplength=400,
                                 fg="red")
        warning_label["text"] = (
            "Warning: Clicking Start will freeze the UI until the "
            "trigger condition is met. Real-world applications should "
            "run the a_trig method on a separate thread.")
        warning_label.grid(row=curr_row, columnspan=2, sticky=tk.W)

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.start_button = tk.Button(button_frame)
        self.start_button["text"] = "Start"
        self.start_button["command"] = self.start
        self.start_button.grid(row=0, column=0, padx=3, pady=3)

        quit_button = tk.Button(button_frame)
        quit_button["text"] = "Quit"
        quit_button["command"] = self.master.destroy
        quit_button.grid(row=0, column=1, padx=3, pady=3)
Example #14
0
class ULGT03(UIExample):
    def __init__(self, master):
        super(ULGT03, self).__init__(master)
        self.board_num = 0

        self.max_board_num = ul.get_config(InfoType.GLOBALINFO, 0, 0,
                                           GlobalInfo.NUMBOARDS)
        self.create_widgets()
        self.update_board_info()

    def update_board_info(self):
        info_text = ""

        try:
            # Raises exception is board_num is not valid
            self.device_info = DaqDeviceInfo(self.board_num)

            info_text += self.get_ad_info()
            info_text += self.get_temperature_info()
            info_text += self.get_da_info()
            info_text += self.get_digital_info()
            info_text += self.get_counter_info()
            info_text += self.get_expansion_info()
            # Remove the last "newline" character
            info_text = info_text[:-1]
        except ULError:
            info_text = (
                "No board found at board number " + str(self.board_num) +
                ".\nRun InstaCal to add or remove boards before running this "
                + "program.")
        finally:
            self.info_label["text"] = info_text

    def get_ad_info(self):
        result = ''
        if self.device_info.supports_analog_input:
            ai_info = self.device_info.get_ai_info()
            result = ("Number of A/D channels: " + str(ai_info.num_chans) +
                      "\n")
        return result

    def get_temperature_info(self):
        result = ''
        if self.device_info.supports_temp_input:
            ai_info = self.device_info.get_ai_info()
            result = ("Number of Temperature channels: " +
                      str(ai_info.num_temp_chans) + "\n")
        return result

    def get_da_info(self):
        result = ''
        if self.device_info.supports_analog_output:
            ao_info = self.device_info.get_ao_info()
            result = ("Number of D/A channels: " + str(ao_info.num_chans) +
                      "\n")
        return result

    def get_digital_info(self):
        result = ''
        if self.device_info.supports_digital_io:
            dio_info = self.device_info.get_dio_info()
            for port_num in range(len(dio_info.port_info)):
                result += ("Digital Port #" + str(port_num) + ": " +
                           str(dio_info.port_info[port_num].num_bits) +
                           " bits\n")
        return result

    def get_counter_info(self):
        result = ''
        if self.device_info.supports_counters:
            ctr_info = self.device_info.get_ctr_info()
            result = ("Number of counter devices: " + str(ctr_info.num_chans) +
                      "\n")
        return result

    def get_expansion_info(self):
        result = ''
        if self.device_info.num_expansions > 0:
            for exp_info in self.device_info.exp_info:
                result += ("A/D channel " + str(exp_info.mux_ad_chan) +
                           " connected to EXP (device ID=" +
                           str(exp_info.board_type) + ").\n")
        return result

    def board_num_changed(self, *args):
        try:
            self.board_num = int(self.board_num_variable.get())
            self.update_board_info()
        except ValueError:
            self.board_num = 0

    def create_widgets(self):
        '''Create the tkinter UI'''
        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)

        positive_int_vcmd = self.register(validate_positive_int_entry)

        board_num_label = tk.Label(main_frame)
        board_num_label["text"] = "Board Number:"
        board_num_label.grid(row=0, column=0, sticky=tk.W)

        self.board_num_variable = StringVar()
        board_num_entry = tk.Spinbox(main_frame,
                                     from_=0,
                                     to=self.max_board_num,
                                     textvariable=self.board_num_variable,
                                     validate="key",
                                     validatecommand=(positive_int_vcmd, "%P"))
        board_num_entry.grid(row=0, column=1, sticky=tk.W)
        self.board_num_variable.trace("w", self.board_num_changed)

        info_groupbox = tk.LabelFrame(self, text="Board Information")
        info_groupbox.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.info_label = tk.Label(info_groupbox,
                                   justify=tk.LEFT,
                                   wraplength=400)
        self.info_label.grid()

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        quit_button = tk.Button(button_frame)
        quit_button["text"] = "Quit"
        quit_button["command"] = self.master.destroy
        quit_button.grid(row=0, column=0, padx=3, pady=3)
Example #15
0
class ULAI14(UIExample):
    def __init__(self, master=None):
        super(ULAI14, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        use_device_detection = True
        self.board_num = 0

        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            self.ai_info = self.device_info.get_ai_info()
            if self.ai_info.is_supported and self.ai_info.supports_analog_trig:
                self.create_widgets()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets(True)

    def start_scan(self):
        low_chan = self.get_low_channel_num()
        high_chan = self.get_high_channel_num()

        if low_chan > high_chan:
            messagebox.showerror(
                "Error",
                "Low Channel Number must be greater than or equal to "
                "High Channel Number")
            self.start_button["state"] = tk.NORMAL
            return

        rate = 1000
        points_per_channel = 10
        num_channels = high_chan - low_chan + 1
        total_count = points_per_channel * num_channels
        ai_range = self.ai_info.supported_ranges[0]

        trig_type = TrigType.TRIG_ABOVE
        low_threshold_volts = 0.1
        high_threshold_volts = 1.53

        # Allocate a buffer for the scan
        if self.ai_info.resolution <= 16:
            # Use the win_buf_alloc method for devices with a resolution <= 16
            memhandle = ul.win_buf_alloc(total_count)
        else:
            # Use the win_buf_alloc_32 method for devices with a resolution >
            # 16
            memhandle = ul.win_buf_alloc_32(total_count)

        # Check if the buffer was successfully allocated
        if not memhandle:
            messagebox.showerror("Error", "Failed to allocate memory")
            self.start_button["state"] = tk.NORMAL
            return

        try:
            low_threshold, high_threshold = self.get_threshold_counts(
                ai_range, low_threshold_volts, high_threshold_volts)

            ul.set_trigger(self.board_num, trig_type, low_threshold,
                           high_threshold)

            # Run the scan
            ul.a_in_scan(self.board_num, low_chan, high_chan, total_count,
                         rate, ai_range, memhandle, ScanOptions.EXTTRIGGER)

            # Convert the memhandle to a ctypes array
            # Note: the ctypes array will only be valid until win_buf_free
            # is called.
            # A copy of the buffer can be created using win_buf_to_array
            # or win_buf_to_array_32 before the memory is freed. The copy can
            # be used at any time.
            if self.ai_info.resolution <= 16:
                # Use the memhandle_as_ctypes_array method for devices with a
                # resolution <= 16
                array = cast(memhandle, POINTER(c_ushort))
            else:
                # Use the memhandle_as_ctypes_array_32 method for devices with
                # a resolution > 16
                array = cast(memhandle, POINTER(c_ulong))

            # Display the values
            self.display_values(array, ai_range, total_count,
                                low_chan, high_chan)
        except ULError as e:
            show_ul_error(e)
        finally:
            # Free the allocated memory
            ul.win_buf_free(memhandle)
            self.start_button["state"] = tk.NORMAL

    def get_threshold_counts(self, ai_range, low_threshold_volts,
                             high_threshold_volts):
        if self.ai_info.analog_trig_resolution == 0:
            # If the trigger resolution from AnalogInputProps is 0,
            # the resolution of the trigger is the same as the
            # analog input resolution, and we can use from_eng_units
            # to convert from engineering units to count
            low_threshold = ul.from_eng_units(self.board_num, ai_range,
                                              low_threshold_volts)
            high_threshold = ul.from_eng_units(self.board_num, ai_range,
                                               high_threshold_volts)
        else:
            # Otherwise, the resolution of the triggers are different
            # from the analog input, and we must convert from engineering
            # units to count manually

            trig_range = self.ai_info.analog_trig_range
            if trig_range == ULRange.UNKNOWN:
                # If the analog_trig_range is UNKNOWN, the trigger voltage
                # range is the same as the analog input.
                trig_range = ai_range

            low_threshold = self.volts_to_count(
                low_threshold_volts, self.ai_info.analog_trig_resolution,
                trig_range)
            high_threshold = self.volts_to_count(
                high_threshold_volts, self.ai_info.analog_trig_resolution,
                trig_range)

        return low_threshold, high_threshold

    def volts_to_count(self, volts, resolution, voltage_range):
        full_scale_count = 2 ** resolution
        range_min = voltage_range.range_min
        range_max = voltage_range.range_max
        return (full_scale_count / (range_max - range_min)
                * (volts - range_min))

    def display_values(self, array, range_, total_count, low_chan, high_chan):
        new_data_frame = tk.Frame(self.results_group)

        channel_text = []

        # Add the headers
        for chan_num in range(low_chan, high_chan + 1):
            channel_text.append("Channel " + str(chan_num) + "\n")

        chan_count = high_chan - low_chan + 1

        # Add (up to) the first 10 values for each channel to the text
        chan_num = low_chan
        for data_index in range(0, min(chan_count * 10, total_count)):
            if self.ai_info.resolution <= 16:
                eng_value = ul.to_eng_units(
                    self.board_num, range_, array[data_index])
            else:
                eng_value = ul.to_eng_units_32(
                    self.board_num, range_, array[data_index])
            channel_text[chan_num -
                         low_chan] += '{:.3f}'.format(eng_value) + "\n"
            if chan_num == high_chan:
                chan_num = low_chan
            else:
                chan_num += 1

        # Add the labels for each channel
        for chan_num in range(low_chan, high_chan + 1):
            chan_label = tk.Label(new_data_frame, justify=tk.LEFT, padx=3)
            chan_label["text"] = channel_text[chan_num - low_chan]
            chan_label.grid(row=0, column=chan_num - low_chan)

        self.data_frame.destroy()
        self.data_frame = new_data_frame
        self.data_frame.grid()

    def start(self):
        self.start_button["state"] = tk.DISABLED
        self.start_scan()

    def get_low_channel_num(self):
        if self.ai_info.num_chans == 1:
            return 0
        try:
            return int(self.low_channel_entry.get())
        except ValueError:
            return 0

    def get_high_channel_num(self):
        if self.ai_info.num_chans == 1:
            return 0
        try:
            return int(self.high_channel_entry.get())
        except ValueError:
            return 0

    def validate_channel_entry(self, p):
        if p == '':
            return True
        try:
            value = int(p)
            if value < 0 or value > self.ai_info.num_chans - 1:
                return False
        except ValueError:
            return False

        return True

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num)
                                     + ": " + self.device_info.product_name
                                     + " (" + self.device_info.unique_id + ")")

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)

        curr_row = 0
        if self.ai_info.num_chans > 1:
            channel_vcmd = self.register(self.validate_channel_entry)

            low_channel_entry_label = tk.Label(main_frame)
            low_channel_entry_label["text"] = "Low Channel Number:"
            low_channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.low_channel_entry = tk.Spinbox(
                main_frame, from_=0,
                to=max(self.ai_info.num_chans - 1, 0),
                validate='key', validatecommand=(channel_vcmd, '%P'))
            self.low_channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)

            curr_row += 1
            high_channel_entry_label = tk.Label(main_frame)
            high_channel_entry_label["text"] = "High Channel Number:"
            high_channel_entry_label.grid(
                row=curr_row, column=0, sticky=tk.W)

            self.high_channel_entry = tk.Spinbox(
                main_frame, from_=0, validate='key',
                to=max(self.ai_info.num_chans - 1, 0),
                validatecommand=(channel_vcmd, '%P'))
            self.high_channel_entry.grid(
                row=curr_row, column=1, sticky=tk.W)
            initial_value = min(self.ai_info.num_chans - 1, 3)
            self.high_channel_entry.delete(0, tk.END)
            self.high_channel_entry.insert(0, str(initial_value))

            curr_row += 1

        self.results_group = tk.LabelFrame(
            self, text="Results", padx=3, pady=3)
        self.results_group.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.data_frame = tk.Frame(self.results_group)
        self.data_frame.grid()

        curr_row += 1
        warning_label = tk.Label(
            self, justify=tk.LEFT, wraplength=400, fg="red")
        warning_label["text"] = (
            "Warning: Clicking Start will freeze the UI until the "
            "trigger condition is met. Real-world applications should "
            "run the a_in_scan method on a separate thread or use the "
            "BACKGROUND option.")
        warning_label.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.start_button = tk.Button(button_frame)
        self.start_button["text"] = "Start"
        self.start_button["command"] = self.start
        self.start_button.grid(row=0, column=0, padx=3, pady=3)

        quit_button = tk.Button(button_frame)
        quit_button["text"] = "Quit"
        quit_button["command"] = self.master.destroy
        quit_button.grid(row=0, column=1, padx=3, pady=3)
Example #16
0
class ULAI10(UIExample):
    def __init__(self, master=None):
        super(ULAI10, self).__init__(master)
        # By default, the example detects all available devices and selects the
        # first device listed.
        # If use_device_detection is set to False, the board_num property needs
        # to match the desired board number configured with Instacal.
        use_device_detection = True
        self.board_num = 0

        self.num_elements = 4
        self.queue_loaded = False

        try:
            if use_device_detection:
                self.configure_first_detected_device()

            self.device_info = DaqDeviceInfo(self.board_num)
            self.ai_info = self.device_info.get_ai_info()
            if self.ai_info.is_supported:
                self.create_widgets()
                self.scan_loop()
            else:
                self.create_unsupported_widgets()
        except ULError:
            self.create_unsupported_widgets(True)

    def scan_loop(self):
        rate = 100
        points_per_channel = 10
        low_chan = 0  # Ignored by a_in_scan when queue is enabled
        high_chan = 3  # Ignored by a_in_scan when queue is enabled
        num_channels = high_chan - low_chan + 1
        total_count = points_per_channel * num_channels

        # Ignored by a_in_scan when queue is enabled
        range_ = self.ai_info.supported_ranges[0]

        # Allocate a buffer for the scan
        if self.ai_info.resolution <= 16:
            # Use the win_buf_alloc method for devices with a resolution <= 16
            memhandle = ul.win_buf_alloc(total_count)
        else:
            # Use the win_buf_alloc_32 method for devices with a resolution >
            # 16
            memhandle = ul.win_buf_alloc_32(total_count)

        # Check if the buffer was successfully allocated
        if not memhandle:
            messagebox.showerror("Error", "Failed to allocate memory")
            return

        try:
            # Run the scan
            ul.a_in_scan(self.board_num, low_chan, high_chan, total_count,
                         rate, range_, memhandle, 0)

            # Convert the memhandle to a ctypes array
            # Note: the ctypes array will only be valid until win_buf_free
            # is called.
            # A copy of the buffer can be created using win_buf_to_array
            # or win_buf_to_array_32 before the memory is freed. The copy can
            # be used at any time.
            if self.ai_info.resolution <= 16:
                # Use the memhandle_as_ctypes_array method for devices with a
                # resolution <= 16
                array = cast(memhandle, POINTER(c_ushort))
            else:
                # Use the memhandle_as_ctypes_array_32 method for devices with
                # a resolution > 16
                array = cast(memhandle, POINTER(c_ulong))

            # Display the values
            self.display_values(array, total_count)

            self.after(1000, self.scan_loop)
        except ULError as e:
            show_ul_error(e)
        finally:
            # Free the allocated memory
            ul.win_buf_free(memhandle)

    def display_values(self, array, total_count):
        data_text = []

        for _ in range(0, self.num_elements):
            data_text.append("")

        # Add (up to) the first 10 values for each channel to the text
        chan_num = 0
        for data_index in range(0, min(self.num_elements * 10, total_count)):
            data_text[chan_num] += str(array[data_index]) + "\n"
            if chan_num == self.num_elements - 1:
                chan_num = 0
            else:
                chan_num += 1

        # Add the labels for each channel
        for chan_num in range(0, self.num_elements):
            self.data_labels[chan_num]["text"] = data_text[chan_num]

    def toggle_load_queue(self):
        if not self.queue_loaded:
            chan_array = []
            if self.random_channels_checkbutton_var.get():
                for chan_num in range(0, self.num_elements):
                    chan_array.append(
                        random.randint(0, self.ai_info.num_chans - 1))
            else:
                for chan_num in range(0, self.num_elements):
                    chan_array.append(chan_num)

            gain_array = []
            if self.random_ranges_checkbutton_var.get():
                for chan_num in range(0, self.num_elements):
                    gain_array.append(
                        random.choice(self.ai_info.supported_ranges))
            else:
                range_ = self.ai_info.supported_ranges[0]
                for chan_num in range(0, self.num_elements):
                    gain_array.append(range_)

            try:
                ul.a_load_queue(self.board_num, chan_array, gain_array,
                                self.num_elements)

                self.queue_loaded = True
                self.toggle_load_queue_button["text"] = "Unload Queue"
                self.instructions_label["text"] = ("Queue loaded on board " +
                                                   str(self.board_num))

                # Update the headers
                for chan_num in range(0, self.num_elements):
                    self.channel_labels[chan_num]["text"] = (
                        "Channel " + str(chan_array[chan_num]))
                for chan_num in range(0, self.num_elements):
                    self.range_labels[chan_num]["text"] = \
                        gain_array[chan_num].name
            except ULError as e:
                if e.errorcode == ErrorCode.BADADCHAN:
                    self.instructions_label["text"] = (
                        "Board " + str(self.board_num) +
                        " doesn't support random channels. Queue was not "
                        "changed.")
                else:
                    raise
        else:
            # Set Count to 0 to disable the queue
            ul.a_load_queue(self.board_num, [], [], 0)

            self.queue_loaded = False
            self.toggle_load_queue_button["text"] = "Load Queue"
            self.instructions_label["text"] = (
                "Board " + str(self.board_num) +
                " scanning contiguous channels with with Range set to " +
                str(self.ai_info.supported_ranges[0]))

            # Update the headers
            for chan_num in range(0, self.num_elements):
                self.channel_labels[chan_num]["text"] = ("Channel " +
                                                         str(chan_num))
            for chan_num in range(0, self.num_elements):
                self.range_labels[chan_num]["text"] = (
                    self.ai_info.supported_ranges[0].name)

    def create_widgets(self):
        '''Create the tkinter UI'''
        self.device_label = tk.Label(self)
        self.device_label.pack(fill=tk.NONE, anchor=tk.NW)
        self.device_label["text"] = ('Board Number ' + str(self.board_num) +
                                     ": " + self.device_info.product_name +
                                     " (" + self.device_info.unique_id + ")")

        main_frame = tk.Frame(self)
        main_frame.pack(fill=tk.X, anchor=tk.NW)

        self.instructions_label = tk.Label(main_frame,
                                           justify=tk.LEFT,
                                           wraplength=400)
        self.instructions_label["text"] = (
            "Board " + str(self.board_num) +
            " collecting analog data on up to " + str(self.num_elements) +
            " channels between channel 0 and channel " +
            str(self.ai_info.num_chans) + " using AInScan and ALoadQueue.")
        self.instructions_label.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.results_group = tk.LabelFrame(main_frame,
                                           text="Results",
                                           padx=3,
                                           pady=3)
        self.results_group.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.data_frame = tk.Frame(self.results_group)
        self.data_frame.grid()

        self.channel_labels = []
        self.range_labels = []
        self.data_labels = []
        # Add the labels for each channel
        for chan_num in range(0, self.num_elements):
            chan_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
            chan_label.grid(row=0, column=chan_num)
            chan_label["text"] = "Channel " + str(chan_num)
            self.channel_labels.append(chan_label)

            range_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
            range_label.grid(row=1, column=chan_num)
            range_label["text"] = self.ai_info.supported_ranges[0].name
            self.range_labels.append(range_label)

            data_label = tk.Label(self.data_frame, justify=tk.LEFT, padx=3)
            data_label.grid(row=2, column=chan_num)
            self.data_labels.append(data_label)

        self.random_ranges_checkbutton_var = IntVar(value=1)
        random_ranges_checkbutton = tk.Checkbutton(
            main_frame,
            text="Random Ranges",
            variable=self.random_ranges_checkbutton_var,
            borderwidth=0)
        random_ranges_checkbutton.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3)

        self.random_channels_checkbutton_var = IntVar(value=0)
        random_channels_checkbutton = tk.Checkbutton(
            main_frame,
            text="Random Channels",
            variable=self.random_channels_checkbutton_var,
            borderwidth=0)
        random_channels_checkbutton.pack(fill=tk.X,
                                         anchor=tk.NW,
                                         padx=3,
                                         pady=3)

        button_frame = tk.Frame(self)
        button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE)

        self.toggle_load_queue_button = tk.Button(button_frame)
        self.toggle_load_queue_button["text"] = "Load Queue"
        self.toggle_load_queue_button["command"] = \
            self.toggle_load_queue
        self.toggle_load_queue_button.grid(row=0,
                                           column=1,
                                           rowspan=2,
                                           padx=3,
                                           pady=3)

        quit_button = tk.Button(button_frame)
        quit_button["text"] = "Quit"
        quit_button["command"] = self.master.destroy
        quit_button.grid(row=0, column=2, rowspan=2, padx=3, pady=3)