1+ import os
2+ import sys
3+ import subprocess
4+ import time
5+ from pathlib import Path
6+
7+ # Metadata & Terms
8+ APP_NAME = "PICA Command Line Interface"
9+ VERSION = "1.0.1"
10+ AUTHORS = "Prathamesh Deshmukh, Sudip Mukherjee"
11+ AFFILIATION = "UGC-DAE Consortium for Scientific Research, Mumbai Centre"
12+ LICENSE = "MIT License"
13+ TERMS = """
14+ TERMS OF SERVICE / DISCLAIMER:
15+ This software is provided "as is", without warranty of any kind.
16+ The authors are not responsible for any damage to hardware instruments
17+ (Keithley, Lakeshore, etc.) caused by improper configuration or
18+ misuse of these control scripts.
19+ Always verify safety limits (Compliance, Max Voltage) before execution.
20+ """
21+
22+ def print_banner ():
23+ """Prints the professional header."""
24+ print ("\033 [H\033 [J" ) # Clear screen
25+ print ("=" * 60 )
26+ print (f" { APP_NAME } (v{ VERSION } )" )
27+ print (f" { AFFILIATION } " )
28+ print ("-" * 60 )
29+ print (f" Authors: { AUTHORS } " )
30+ print (f" License: { LICENSE } " )
31+ print ("=" * 60 )
32+ print (TERMS )
33+ print ("=" * 60 )
34+ print ("\n " )
35+
36+ def find_scripts (base_path ):
37+ """
38+ Recursively finds all python files ending with 'Instrument_Control.py'.
39+ Returns a list of tuples: (Display Name, Full Path)
40+ """
41+ scripts = []
42+ base = Path (base_path )
43+
44+ # Exclude development/utility scripts that are not main measurement modules
45+ exclude_list = [
46+ "BasicTest_S830_Instrument_Control.py" ,
47+ "GPIB_InterfaceTest_Simple_Instrument_Control.py" ,
48+ ]
49+
50+ for path in base .rglob ("*Instrument_Control.py" ):
51+ if path .name in exclude_list :
52+ continue
53+
54+ # Create a readable name from the filename
55+ # e.g., 'IV_K2400_Loop_Instrument_Control.py' -> 'IV K2400 Loop'
56+ name = path .stem .replace ("_Instrument_Control" , "" ).replace ("_" , " " )
57+
58+ # Get path relative to the run location for clarity, or absolute
59+ scripts .append ((name , str (path )))
60+
61+ return sorted (scripts )
62+
63+ def run_script (script_path ):
64+ """Runs the selected script using the current python interpreter."""
65+ print (f"\n [INFO] Module: { os .path .basename (script_path )} " )
66+ print ("[INFO] Enter arguments below, or press ENTER for defaults." )
67+
68+ args = input ("Arguments > " ).strip ()
69+ cmd = [sys .executable , script_path ]
70+ if args :
71+ cmd .extend (args .split ())
72+
73+ try :
74+ print ("-" * 60 )
75+ subprocess .run (cmd )
76+ print ("-" * 60 )
77+ print ("\n [SUCCESS] Execution finished." )
78+ except KeyboardInterrupt :
79+ print ("\n [WARN] Execution interrupted by user." )
80+ except Exception as e :
81+ print (f"\n [ERROR] Failed to run script: { e } " )
82+
83+ input ("\n Press ENTER to return to menu..." )
84+
85+ def main ():
86+ # Detect where the 'pica' package is located
87+ current_dir = os .path .dirname (os .path .abspath (__file__ ))
88+
89+ while True :
90+ print_banner ()
91+ print ("Scannning for available measurement modules...\n " )
92+
93+ scripts = find_scripts (current_dir )
94+
95+ if not scripts :
96+ print ("[ERROR] No 'Instrument_Control.py' scripts found in pica/ directory." )
97+ sys .exit (1 )
98+
99+ print (f"{ 'No.' :<4} | { 'Module Name' } " )
100+ print ("-" * 40 )
101+
102+ for idx , (name , path ) in enumerate (scripts , 1 ):
103+ print (f"{ idx :<4} | { name } " )
104+
105+ print ("-" * 40 )
106+ print (f"{ 'Q' :<4} | Quit CLI" )
107+
108+ choice = input ("\n Select a module number: " ).strip ().lower ()
109+
110+ if choice == 'q' :
111+ print ("Exiting PICA CLI. Goodbye!" )
112+ sys .exit (0 )
113+
114+ try :
115+ idx = int (choice )
116+ if 1 <= idx <= len (scripts ):
117+ selected_name , selected_path = scripts [idx - 1 ]
118+ run_script (selected_path )
119+ else :
120+ print (f"[ERROR] Please enter a number between 1 and { len (scripts )} " )
121+ time .sleep (1.5 )
122+ except ValueError :
123+ print ("[ERROR] Invalid input. Enter a number or 'Q'." )
124+ time .sleep (1.5 )
125+
126+ if __name__ == "__main__" :
127+ main ()
0 commit comments