|
24 | 24 | import multiprocessing |
25 | 25 | from multiprocessing import Process |
26 | 26 |
|
| 27 | +from pica.utils.GPIB_Instrument_Scanner_GUI import GPIB_Instrument_Scanner_GUI |
| 28 | + |
27 | 29 | try: |
28 | 30 | from PIL import Image, ImageTk |
29 | 31 | PIL_AVAILABLE = True |
@@ -779,8 +781,9 @@ def run_gpib_test(self): |
779 | 781 | "Dependency Missing", |
780 | 782 | "The 'pyvisa' library is required.\n\nInstall via pip:\npip install pyvisa pyvisa-py") |
781 | 783 | return |
782 | | - # The GPIB scanner is now its own class |
783 | | - GPIBScannerWindow(self.root, self) |
| 784 | + # The GPIB scanner is now its own class, create a new window for it |
| 785 | + scanner_window = Toplevel(self.root) |
| 786 | + GPIB_Instrument_Scanner_GUI(scanner_window) |
784 | 787 |
|
785 | 788 | def _pre_cache_markdown_files(self): |
786 | 789 | """ |
@@ -914,175 +917,6 @@ def _render_markdown_content(self, text_area, lines): |
914 | 917 | text_area.insert('end', '\n') |
915 | 918 |
|
916 | 919 |
|
917 | | -class GPIBScannerWindow(Toplevel): |
918 | | - def __init__(self, parent, app_ref): |
919 | | - super().__init__(parent) |
920 | | - self.app = app_ref # Reference to the main app for styling and logging |
921 | | - |
922 | | - self.title("GPIB/VISA Instrument Scanner") |
923 | | - self.configure(bg=self.app.CLR_BG_DARK) |
924 | | - self.transient(parent) |
925 | | - |
926 | | - # --- Position the window to the top-right of the screen --- |
927 | | - win_width, win_height = 500, 400 |
928 | | - self.update_idletasks() |
929 | | - screen_width = self.winfo_screenwidth() |
930 | | - x_pos = screen_width - win_width - 50 |
931 | | - y_pos = 50 |
932 | | - self.geometry(f"{win_width}x{win_height}+{x_pos}+{y_pos}") |
933 | | - self.minsize(500, 350) |
934 | | - |
935 | | - self.result_queue = queue.Queue() |
936 | | - self.create_widgets() |
937 | | - |
938 | | - self.app.log( |
939 | | - "GPIB/VISA scanner window opened. Auto-scan will begin shortly.") |
940 | | - self.after(100, self._process_gpib_queue) # Start the queue processor |
941 | | - # Auto-start the scan after 1 second |
942 | | - self.after(1000, self.start_scan) |
943 | | - |
944 | | - def create_widgets(self): |
945 | | - main_frame = ttk.Frame(self, padding=15) |
946 | | - main_frame.pack(fill='both', expand=True) |
947 | | - main_frame.rowconfigure(1, weight=1) |
948 | | - main_frame.columnconfigure(0, weight=1) |
949 | | - |
950 | | - controls_frame = ttk.Frame(main_frame) |
951 | | - controls_frame.grid(row=0, column=0, sticky='ew', pady=(0, 15)) |
952 | | - controls_frame.columnconfigure((0, 1, 2), weight=1) |
953 | | - |
954 | | - self.console_area = scrolledtext.ScrolledText( |
955 | | - main_frame, |
956 | | - state='disabled', |
957 | | - bg=self.app.CLR_CONSOLE_BG, |
958 | | - fg=self.app.CLR_TEXT, |
959 | | - font=self.app.FONT_CONSOLE, |
960 | | - wrap='word', |
961 | | - bd=0) |
962 | | - self.console_area.grid(row=1, column=0, sticky='nsew') |
963 | | - |
964 | | - self.scan_button = ttk.Button( |
965 | | - controls_frame, |
966 | | - text="Scan Instruments", |
967 | | - command=self.start_scan, |
968 | | - style='Scan.TButton') |
969 | | - self.scan_button.grid(row=0, column=0, padx=(0, 5), sticky='ew') |
970 | | - guide_button = ttk.Button( |
971 | | - controls_frame, |
972 | | - text="Address Guide", |
973 | | - command=self.show_address_guide, |
974 | | - style='App.TButton') |
975 | | - guide_button.grid(row=0, column=1, padx=5, sticky='ew') |
976 | | - clear_button = ttk.Button( |
977 | | - controls_frame, |
978 | | - text="Clear Log", |
979 | | - command=self.clear_log, |
980 | | - style='App.TButton') |
981 | | - clear_button.grid(row=0, column=2, padx=(5, 0), sticky='ew') |
982 | | - |
983 | | - ttk.Button( |
984 | | - main_frame, |
985 | | - text="Close", |
986 | | - style='App.TButton', |
987 | | - command=self.destroy).grid( |
988 | | - row=2, column=0, |
989 | | - sticky='ew', |
990 | | - pady=( |
991 | | - 15, |
992 | | - 0)) |
993 | | - self.log_to_scanner("Welcome to the GPIB/VISA Instrument Scanner.") |
994 | | - self.log_to_scanner("Auto-scanning for instruments in 1 second...") |
995 | | - |
996 | | - def log_to_scanner(self, message, add_timestamp=True): |
997 | | - self.console_area.config(state='normal') |
998 | | - if add_timestamp: |
999 | | - timestamp = datetime.now().strftime("%H:%M:%S") |
1000 | | - self.console_area.insert('end', f"[{timestamp}] {message}\n") |
1001 | | - else: |
1002 | | - self.console_area.insert('end', message) |
1003 | | - self.console_area.see('end') |
1004 | | - self.console_area.config(state='disabled') |
1005 | | - |
1006 | | - def start_scan(self): |
1007 | | - self.scan_button.config(state='disabled') |
1008 | | - self.log_to_scanner("Starting scan...") |
1009 | | - threading.Thread(target=self._gpib_scan_worker, daemon=True).start() |
1010 | | - |
1011 | | - def clear_log(self): |
1012 | | - self.console_area.config(state='normal') |
1013 | | - self.console_area.delete(1.0, 'end') |
1014 | | - self.console_area.config(state='disabled') |
1015 | | - self.log_to_scanner("Log cleared.") |
1016 | | - |
1017 | | - def show_address_guide(self): |
1018 | | - guide_text = """ |
1019 | | ---- PICA Instrument Address Guide --- |
1020 | | -Note: These are typical addresses. Use the scan results for exact values. |
1021 | | -
|
1022 | | -Temperature Controllers |
1023 | | - • Lakeshore 340: GPIB0::12::INSTR |
1024 | | - • Lakeshore 350: GPIB1::15::INSTR |
1025 | | -
|
1026 | | -Source-Measure Units (SMU) & Electrometers |
1027 | | - • Keithley 2400: GPIB1::4::INSTR |
1028 | | - • Keithley 6221: GPIB0::13::INSTR |
1029 | | - • Keithley 6517B: GPIB1::27::INSTR |
1030 | | -
|
1031 | | -Nanovoltmeters, LCR Meters & Amplifiers |
1032 | | - • Keithley 2182: GPIB0::7::INSTR |
1033 | | - • Keysight E4980A: GPIB0::17::INSTR |
1034 | | - • SRS SR830 Lock-in: GPIB0::8::INSTR |
1035 | | - • Stanford PS365 HV: GPIB0::14::INSTR |
1036 | | -
|
1037 | | ---------------------------------------------- |
1038 | | -""" |
1039 | | - self.log_to_scanner(guide_text, add_timestamp=False) |
1040 | | - |
1041 | | - def _gpib_scan_worker(self): |
1042 | | - try: |
1043 | | - rm = pyvisa.ResourceManager() |
1044 | | - resources = rm.list_resources() |
1045 | | - if not resources: |
1046 | | - self.result_queue.put( |
1047 | | - "-> No instruments found. Check connections and retry.\n") |
1048 | | - else: |
1049 | | - self.result_queue.put( |
1050 | | - f"-> Found {len(resources)} instrument(s). Querying...\n\n") |
1051 | | - for address in resources: |
1052 | | - try: |
1053 | | - with rm.open_resource(address) as instrument: |
1054 | | - instrument.timeout = 2000 |
1055 | | - idn = instrument.query('*IDN?').strip() |
1056 | | - result = f"Address: {address}\n ID: {idn}\n\n" |
1057 | | - self.result_queue.put(result) |
1058 | | - except Exception as e: |
1059 | | - result = f"Address: {address}\n Error: Could not get ID. {e}\n\n" |
1060 | | - self.result_queue.put(result) |
1061 | | - except pyvisa.errors.VisaIOError: |
1062 | | - error_msg = ( |
1063 | | - "PICA could not find a VISA backend. Please install NI-VISA or run pip install pyvisa-py.\n" |
1064 | | - "Refer to the 'Troubleshooting Installation' section in the documentation for more details.\n") |
1065 | | - self.result_queue.put(error_msg) |
1066 | | - except Exception as e: |
1067 | | - error_msg = ( |
1068 | | - f"A critical VISA error occurred: {e}\n" |
1069 | | - "Please ensure a VISA backend (e.g., NI-VISA) is installed correctly.\n") |
1070 | | - self.result_queue.put(error_msg) |
1071 | | - finally: |
1072 | | - self.result_queue.put("SCAN_COMPLETE") |
1073 | | - |
1074 | | - def _process_gpib_queue(self): |
1075 | | - try: |
1076 | | - message = self.result_queue.get_nowait() |
1077 | | - if message == "SCAN_COMPLETE": |
1078 | | - self.scan_button.config(state='normal') |
1079 | | - self.log_to_scanner("Scan complete.") |
1080 | | - else: |
1081 | | - self.log_to_scanner(message, add_timestamp=False) |
1082 | | - except queue.Empty: |
1083 | | - pass |
1084 | | - finally: |
1085 | | - self.after(100, self._process_gpib_queue) |
1086 | 920 |
|
1087 | 921 |
|
1088 | 922 | def main(): |
|
0 commit comments