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_output: raise Exception('Error: The DAQ device does not support ' 'analog output') print('\nActive DAQ device: ', daq_dev_info.product_name, ' (', daq_dev_info.unique_id, ')\n', sep='') ao_info = daq_dev_info.get_ao_info() ao_range = ao_info.supported_ranges[0] channel = 0 data_value = ao_range.range_max / 2 print('Outputting', data_value, 'Volts to channel', channel) # Send the value to the device (optional parameter omitted) ul.v_out(board_num, channel, ao_range, data_value) except Exception as e: print('\n', e) finally: if use_device_detection: ul.release_daq_device(board_num)
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)
class ULAO02(UIExample): def __init__(self, master=None): super(ULAO02, 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.ao_info = self.device_info.get_ao_info() if self.ao_info.is_supported and self.ao_info.supports_scan: self.create_widgets() else: self.create_unsupported_widgets() except ULError: self.create_unsupported_widgets(True) def send_data(self): # Build the data array num_chans = min(self.ao_info.num_chans, 4) num_points = num_chans ao_range = self.ao_info.supported_ranges[0] memhandle = ul.win_buf_alloc(num_points) # Check if the buffer was successfully allocated if not memhandle: messagebox.showerror("Error", "Failed to allocate memory") self.send_data["state"] = tk.NORMAL return try: data_array = cast(memhandle, POINTER(c_ushort)) full_scale_count = (2**self.ao_info.resolution) - 1 value_step = full_scale_count / (num_chans + 1) for point_num in range(0, num_points): raw_value = int(value_step * (point_num + 1)) data_array[point_num] = raw_value self.raw_data_labels[point_num]["text"] = str(raw_value) # ul.to_eng_units cannot be used here, as it uses the analog # input resolution. Instead, do the conversion on our own. volts = self.ao_to_eng_units(raw_value, ao_range, self.ao_info.resolution) self.volts_labels[point_num]["text"] = ('{:.3f}'.format(volts)) ul.a_out_scan(self.board_num, 0, num_chans - 1, num_points, 100, ao_range, memhandle, 0) except ULError as e: show_ul_error(e) finally: ul.win_buf_free(memhandle) def ao_to_eng_units(self, raw_value, ao_range, resolution): full_scale_volts = ao_range.range_max - ao_range.range_min full_scale_count = (2**resolution) - 1 return ((full_scale_volts / full_scale_count) * raw_value + ao_range.range_min) 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) data_frame = tk.Frame(main_frame) data_frame.pack(fill=tk.X, anchor=tk.NW) raw_data_label = tk.Label(data_frame) raw_data_label["text"] = "Raw Data" raw_data_label.grid(row=1, sticky=tk.W) volts_label = tk.Label(data_frame) volts_label["text"] = "Volts" volts_label.grid(row=2, sticky=tk.W) self.raw_data_labels = [] self.volts_labels = [] for chan_num in range(0, min(self.ao_info.num_chans, 4)): name_label = tk.Label(data_frame) name_label["text"] = "Channel " + str(chan_num) name_label.grid(row=0, column=chan_num + 1, sticky=tk.W) raw_data_label = tk.Label(data_frame) raw_data_label.grid(row=1, column=chan_num + 1, sticky=tk.W) self.raw_data_labels.append(raw_data_label) volts_label = tk.Label(data_frame) volts_label.grid(row=2, column=chan_num + 1, sticky=tk.W) self.volts_labels.append(volts_label) button_frame = tk.Frame(self) button_frame.pack(fill=tk.X, side=tk.RIGHT, anchor=tk.SE) send_data_button = tk.Button(button_frame) send_data_button["text"] = "Start" send_data_button["command"] = self.send_data send_data_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)
class VOut01(UIExample): def __init__(self, master=None): super(VOut01, 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.ao_info = self.device_info.get_ao_info() if self.ao_info.is_supported and self.ao_info.supports_v_out: self.create_widgets() else: self.create_unsupported_widgets() except ULError: self.create_unsupported_widgets(True) def update_value(self): channel = self.get_channel_num() ao_range = self.ao_info.supported_ranges[0] data_value = self.get_data_value() try: # Send the value to the device (optional parameter omitted) ul.v_out(self.board_num, channel, ao_range, data_value) except ULError as e: show_ul_error(e) def get_data_value(self): try: return float(self.data_value_entry.get()) except ValueError: return 0 def get_channel_num(self): if self.ao_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.ao_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 if self.ao_info.num_chans > 1: 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.ao_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 data_value_label = tk.Label(main_frame) data_value_label["text"] = "Value (V):" data_value_label.grid(row=curr_row, column=0, sticky=tk.W) self.data_value_entry = tk.Entry( main_frame, validate='key', validatecommand=(float_vcmd, '%P')) self.data_value_entry.grid(row=curr_row, column=1, sticky=tk.W) self.data_value_entry.insert(0, "0") update_button = tk.Button(main_frame) update_button["text"] = "Update" update_button["command"] = self.update_value update_button.grid(row=curr_row, column=2, padx=3, pady=3) 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)
class DaqOutScan01(UIExample): def __init__(self, master=None): super(DaqOutScan01, 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_chans = 2 self.chan_list = [] self.chan_type_list = [] self.gain_list = [] try: if use_device_detection: self.configure_first_detected_device() self.device_info = DaqDeviceInfo(self.board_num) if self.device_info.supports_daq_output: self.ao_info = self.device_info.get_ao_info() 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): daqo_info = self.device_info.get_daqo_info() supported_channel_types = daqo_info.supported_channel_types # Add an analog output channel self.chan_list.append(0) self.chan_type_list.append(ChannelType.ANALOG) self.gain_list.append(self.ao_info.supported_ranges[0]) # Add a digital output channel if ChannelType.DIGITAL16 in supported_channel_types: chan_type = ChannelType.DIGITAL16 elif ChannelType.DIGITAL8 in supported_channel_types: chan_type = ChannelType.DIGITAL8 else: chan_type = ChannelType.DIGITAL 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) # Configure all digital ports for output for port in dio_info.port_info: if port.is_port_configurable: ul.d_config_port(self.board_num, port.type, DigitalIODirection.OUT) def start_scan(self): # Build the data array points_per_channel = 1000 rate = 1000 num_points = self.num_chans * points_per_channel scan_options = ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS ao_range = self.ao_info.supported_ranges[0] self.memhandle = ul.win_buf_alloc(num_points) # 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: data_array = cast(self.memhandle, POINTER(c_ushort)) freq = self.add_example_data(data_array, ao_range, rate, points_per_channel) self.freq_label["text"] = str(freq) + "Hz" ul.daq_out_scan(self.board_num, self.chan_list, self.chan_type_list, self.gain_list, self.num_chans, rate, num_points, self.memhandle, scan_options) # Start updating the displayed values self.update_displayed_values() except ULError as e: show_ul_error(e) self.set_ui_idle_state() return def add_example_data(self, data_array, ao_range, rate, points_per_channel): # Calculate a frequency that will work well with the size of the array freq = rate / points_per_channel # 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 for the analog channel, and square # wave data for all bits on the digital port. data_index = 0 for point_num in range(0, points_per_channel): # Generate a value in volts for output from the analog channel value_volts = amplitude * math.sin( 2 * math.pi * freq * point_num / rate) + y_offset # Convert the volts to counts value_count = ul.from_eng_units(self.board_num, ao_range, value_volts) data_array[data_index] = value_count data_index += 1 # Generate a value for output from the digital port if point_num < points_per_channel / 2: data_array[data_index] = 0 else: data_array[data_index] = 0xFFFF data_index += 1 return freq def update_displayed_values(self): # Get the status from the device status, curr_count, curr_index = ul.get_status( self.board_num, FunctionType.DAQOFUNCTION) # Display the status info self.update_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_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 stop(self): ul.stop_background(self.board_num, FunctionType.DAQOFUNCTION) def exit(self): self.stop() self.master.destroy() 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) results_frame = tk.Frame(main_frame) results_frame.pack(fill=tk.X, anchor=tk.NW) curr_row = 0 status_left_label = tk.Label(results_frame) status_left_label["text"] = "Status:" status_left_label.grid(row=curr_row, column=0, sticky=tk.W) self.status_label = tk.Label(results_frame) 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(results_frame) index_left_label["text"] = "Index:" index_left_label.grid(row=curr_row, column=0, sticky=tk.W) self.index_label = tk.Label(results_frame) 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(results_frame) count_left_label["text"] = "Count:" count_left_label.grid(row=curr_row, column=0, sticky=tk.W) self.count_label = tk.Label(results_frame) self.count_label["text"] = "0" self.count_label.grid(row=curr_row, column=1, sticky=tk.W) curr_row += 1 freq_left_label = tk.Label(results_frame) freq_left_label["text"] = "Frequency:" freq_left_label.grid(row=curr_row, column=0, sticky=tk.W) self.freq_label = tk.Label(results_frame) self.freq_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.exit quit_button.grid(row=0, column=1, padx=3, pady=3)
class ULAO04(UIExample): def __init__(self, master=None): super(ULAO04, 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.ao_info = self.device_info.get_ao_info() if self.ao_info.is_supported and self.ao_info.supports_scan: self.create_widgets() else: self.create_unsupported_widgets() except ULError: self.create_unsupported_widgets(True) def start_scan(self): # Build the data array 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 points_per_channel = 1000 rate = 1000 num_points = self.num_chans * points_per_channel scan_options = (ScanOptions.BACKGROUND | ScanOptions.CONTINUOUS | ScanOptions.SCALEDATA) ao_range = self.ao_info.supported_ranges[0] self.memhandle = ul.scaled_win_buf_alloc(num_points) # 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: data_array = cast(self.memhandle, POINTER(c_double)) frequencies = self.add_example_data(data_array, ao_range, self.num_chans, rate, points_per_channel) self.recreate_freq_frame() self.display_signal_info(frequencies) ul.a_out_scan(self.board_num, self.low_chan, self.high_chan, num_points, rate, ao_range, self.memhandle, scan_options) # Start updating the displayed values self.update_displayed_values() except ULError as e: show_ul_error(e) self.set_ui_idle_state() return def display_signal_info(self, frequencies): for channel_num in range(self.low_chan, self.high_chan + 1): curr_row = channel_num - self.low_chan self.freq_labels[curr_row]["text"] = str( frequencies[curr_row]) + " Hz" def add_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_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_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_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 recreate_freq_frame(self): low_chan = self.low_chan high_chan = self.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(self): ul.stop_background(self.board_num, FunctionType.AOFUNCTION) def exit(self): self.stop() self.master.destroy() 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.ao_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.ao_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.ao_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.ao_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.ao_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, to=max(self.ao_info.num_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.ao_info.num_chans - 1, 3) self.high_channel_entry.delete(0, tk.END) self.high_channel_entry.insert(0, str(initial_value)) scan_info_group = tk.LabelFrame(self, text="Scan Information", padx=3, pady=3) scan_info_group.pack(fill=tk.X, anchor=tk.NW, padx=3, pady=3) scan_info_group.grid_columnconfigure(1, weight=1) curr_row += 1 status_left_label = tk.Label(scan_info_group) status_left_label["text"] = "Status:" status_left_label.grid(row=curr_row, column=0, sticky=tk.W) self.status_label = tk.Label(scan_info_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(scan_info_group) index_left_label["text"] = "Index:" index_left_label.grid(row=curr_row, column=0, sticky=tk.W) self.index_label = tk.Label(scan_info_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(scan_info_group) count_left_label["text"] = "Count:" count_left_label.grid(row=curr_row, column=0, sticky=tk.W) self.count_label = tk.Label(scan_info_group) self.count_label["text"] = "0" self.count_label.grid(row=curr_row, column=1, sticky=tk.W) curr_row += 1 self.freq_inner_frame = tk.Frame(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.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.exit quit_button.grid(row=0, column=1, padx=3, pady=3)
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)
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 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_output: raise Exception('Error: The DAQ device does not support ' 'analog output') print('\nActive DAQ device: ', daq_dev_info.product_name, ' (', daq_dev_info.unique_id, ')\n', sep='') ao_info = daq_dev_info.get_ao_info() low_chan = 0 high_chan = min(3, ao_info.num_chans - 1) num_chans = high_chan - low_chan + 1 rate = 100 points_per_channel = 1000 total_count = points_per_channel * num_chans ao_range = ao_info.supported_ranges[0] # Allocate a buffer for the scan memhandle = ul.win_buf_alloc(total_count) # Convert the 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 # before the memory is freed. The copy can be used at any time. ctypes_array = cast(memhandle, POINTER(c_ushort)) # Check if the buffer was successfully allocated if not memhandle: raise Exception('Error: Failed to allocate memory') frequencies = add_example_data(board_num, ctypes_array, ao_range, num_chans, rate, points_per_channel) for ch_num in range(low_chan, high_chan + 1): print('Channel', ch_num, 'Output Signal Frequency:', frequencies[ch_num - low_chan]) # Start the scan ul.a_out_scan(board_num, low_chan, high_chan, total_count, rate, ao_range, memhandle, ScanOptions.BACKGROUND) # Wait for the scan to complete print('Waiting for output scan to complete...', end='') status = Status.RUNNING while status != Status.IDLE: print('.', end='') # Slow down the status check so as not to flood the CPU sleep(0.5) status, _, _ = ul.get_status(board_num, FunctionType.AOFUNCTION) print('') print('Scan completed successfully') 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)
class MCCDAQ(dev.Device): __registered_board_nums = [] __memhandles = [] def __init__(self, board_num: int, dev_handle: ul.DaqDeviceDescriptor, sampling: params.Sampling): self.dev_info = DaqDeviceInfo(board_num) self.sampling = sampling self.ao_range = self.dev_info.get_ao_info().supported_ranges[0] self.channels = [] self.num_ao_channels: int = self.dev_info.get_ao_info().num_chans self.points_per_channel: int = 1024 self.buffer_size = self.num_ao_channels * self.points_per_channel dev.Device.__init__(self, self.board_num, self.dev_info) if MCCDAQ.__registered_board_nums.index(board_num) == -1: ul.ignore_instacal() ul.create_daq_device(board_num, dev_handle) MCCDAQ.__registered_board_nums.append(board_num) MCCDAQ.__memhandles.append(ul.win_buf_alloc(self.buffer_size)) self.memhandle = MCCDAQ.__memhandles.index(self.board_num) if not self.memhandle: raise Exception('MCCDAQChannel: Failed to allocate memory') self.cdata = cast(self.memhandle, POINTER(c_ushort)) for channel_idx in range(self.num_ao_channels): self.channels.append(MCCDAQChannel(self, channel_idx)) def channel(self, channel_idx): return self.channels[channel_idx] # def analog_out(self, channel_generators: dict, sample_range: range): # channels = channel_generators.keys # generators = channel_generators.values # low_chan = min(channels) # high_chan = max(channels) # num_chans = high_chan - low_chan + 1 # num_samples = min(self.buffer_size, # num_chans * len(sample_range)) # # Generate D/A data: # data_index = 0 # for t in sample_range[:points_per_channel]: # for channel_idx in channels: # self.cdata[data_index] = generators[channel_idx] # # # Send data to D/A: # ul.a_out_scan(board_num = self.board_num, # low_chan = low_chan, # high_chan = high_chan, # num_points = num_samples, # rate = self.sampling.frequency, # ul_range = self.ao_range, # memhandle = self.memhandle, # options = ( enums.ScanOptions.BACKGROUND | # enums.ScanOptions.CONTINUOUS | # enums.ScanOptions.RETRIGMODE ) @classmethod def discover(cls): device_enumeration: list board_num = 0 board_index = 0 for dev_handle in ul.get_daq_device_inventory(InterfaceType.ANY): board_num = board_index board_index = board_index + 1 device_enumeration.append( MCCDAQ(board_num=board_num, dev_handle=dev_handle, sampling=params.Sampling(frequency=100, sample_range={0, 255}))) return device_enumeration