1515from openlifu .io .LIFUUart import LIFUUart
1616from openlifu .plan .solution import Solution
1717
18- REF_MAX_SEQUENCE_TIMES = [2 * 60 , 5 * 60 , 20 * 60 ]
18+ REF_MAX_SEQUENCE_TIMES = {
19+ "default" : [2 * 60 , 5 * 60 , 10 * 60 ], # users to use default values
20+ "stress_test" : [5 * 60 , 9 * 60 , 15 * 60 ] # QA to use stress test values
21+ }
22+
1923REF_MAX_DUTY_CYCLES = [0.05 , 0.1 , 0.2 , 0.3 , 0.4 , 0.5 ]
20- MAX_VOLTAGE_BY_DUTY_CYCLE_AND_SEQUENCE_TIME = [
21- [65 , 65 , 65 ], # 0.05
22- [65 , 65 , 50 ], # 0.1
23- [50 , 40 , 35 ], # 0.2
24- [45 , 35 , 30 ], # 0.3
25- [35 , 30 , 25 ], # 0.4
26- [30 , 25 , 20 ] # 0.5
27- ]
2824
25+ MAX_VOLTAGE_BY_DUTY_CYCLE_AND_SEQUENCE_TIME = {
26+ "evt2" : [
27+ [45 , 45 , 45 ], # 0.05
28+ [40 , 40 , 40 ], # 0.1
29+ [40 , 40 , 35 ], # 0.2
30+ [40 , 35 , 30 ], # 0.3
31+ [35 , 30 , 25 ], # 0.4
32+ [30 , 25 , 20 ] # 0.5
33+ ],
34+ "evt0" : [
35+ [65 , 65 , 65 ], # 0.05
36+ [65 , 65 , 50 ], # 0.1
37+ [50 , 40 , 35 ], # 0.2
38+ [45 , 35 , 30 ], # 0.3
39+ [35 , 30 , 25 ], # 0.4
40+ [30 , 25 , 20 ] # 0.5
41+ ],
42+ }
2943
3044class LIFUInterfaceStatus (Enum ):
3145 STATUS_COMMS_ERROR = - 1
@@ -58,7 +72,9 @@ def __init__(self,
5872 HV_test_mode : bool = False ,
5973 run_async : bool = False ,
6074 ext_power_supply : bool = False ,
61- module_invert : bool | List [bool ] = False ) -> None :
75+ module_invert : bool | List [bool ] = False ,
76+ voltage_table_selection : Optional [str ] = None ,
77+ sequence_time_selection : Optional [str ] = None ) -> None :
6278 """
6379 Initialize the LIFUInterface with given parameters and store them in the class.
6480
@@ -83,6 +99,11 @@ def __init__(self,
8399 self ._hv_uart = None
84100 self .status = LIFUInterfaceStatus .STATUS_SYS_OFF
85101
102+ self .voltage_table = None
103+ self .sequence_time = None
104+ self .voltage_table_selection = voltage_table_selection
105+ self .sequence_time_selection = sequence_time_selection
106+
86107 # Create a TXDevice instance as part of the interface
87108 logger .debug ("Initializing TX Module of LIFUInterface with VID: %s, PID: %s, baudrate: %s, timeout: %s" , vid , tx_pid , baudrate , timeout )
88109 self ._tx_uart = LIFUUart (vid = vid , pid = tx_pid , baudrate = baudrate , timeout = timeout , desc = "TX" , demo_mode = TX_test_mode , async_mode = run_async )
@@ -97,7 +118,6 @@ def __init__(self,
97118 self ._hv_uart = LIFUUart (vid = vid , pid = con_pid , baudrate = baudrate , timeout = timeout , desc = "HV" , demo_mode = HV_test_mode , async_mode = run_async )
98119 self .hvcontroller = HVController (uart = self ._hv_uart )
99120
100-
101121 # Connect signals to internal handlers
102122 if self ._async_mode :
103123 self ._tx_uart .signal_connect .connect (self .signal_connect .emit )
@@ -107,6 +127,31 @@ def __init__(self,
107127 self ._hv_uart .signal_disconnect .connect (self .signal_disconnect .emit )
108128 self ._hv_uart .signal_data_received .connect (self .signal_data_received .emit )
109129
130+ # Temporary fix for hardware variations between EVT0 and EVT2
131+ def _resolve_voltage_chart_evt_version (self , voltage_table : str ) -> list [list [int ]]:
132+ if voltage_table is None :
133+ try :
134+ evt_version = "evt0" if self .hvcontroller .get_version ().startswith ("v1.1" ) else "evt2"
135+ except Exception as e :
136+ logger .error ("Error getting console version: %s" , e )
137+ raise e
138+ else :
139+ evt_version = voltage_table .lower ()
140+ if evt_version not in MAX_VOLTAGE_BY_DUTY_CYCLE_AND_SEQUENCE_TIME :
141+ raise ValueError (f"Invalid voltage_table option '{ voltage_table } '. Valid options are: { tuple (MAX_VOLTAGE_BY_DUTY_CYCLE_AND_SEQUENCE_TIME .keys ())} " )
142+
143+ return MAX_VOLTAGE_BY_DUTY_CYCLE_AND_SEQUENCE_TIME [evt_version ]
144+
145+ # Restrict sequence time options for users vs QA
146+ def _resolve_max_sequence_time_set (self , sequence_time : str ) -> list [int ]:
147+ if sequence_time is None :
148+ return REF_MAX_SEQUENCE_TIMES ["default" ]
149+ else :
150+ sequence_time = sequence_time .lower ()
151+ if sequence_time not in REF_MAX_SEQUENCE_TIMES :
152+ raise ValueError (f"Invalid sequence_time option '{ sequence_time } '. Valid options are: { tuple (REF_MAX_SEQUENCE_TIMES .keys ())} " )
153+ return REF_MAX_SEQUENCE_TIMES [sequence_time ]
154+
110155 async def start_monitoring (self , interval : int = 1 ) -> None :
111156 """Start monitoring for USB device connections."""
112157 try :
@@ -168,11 +213,11 @@ def get_max_voltage(self, solution: Solution | Dict) -> float:
168213 duty_cycle_index = np .where (duty_cycles_limits >= sequence_duty_cycle )[0 ][0 ]
169214
170215 # Find the index of the duration in the reference list
171- duration_limits = np .array (REF_MAX_SEQUENCE_TIMES )
216+ duration_limits = np .array (self . sequence_time )
172217 duration_index = np .where (duration_limits >= sequence_duration )[0 ][0 ]
173218
174219 # Return the maximum voltage for the given duty cycle and duration
175- return MAX_VOLTAGE_BY_DUTY_CYCLE_AND_SEQUENCE_TIME [duty_cycle_index ][duration_index ]
220+ return self . voltage_table [duty_cycle_index ][duration_index ]
176221
177222 def get_max_voltage_table (self ) -> pd .DataFrame :
178223 """
@@ -184,10 +229,10 @@ def get_max_voltage_table(self) -> pd.DataFrame:
184229 data = {
185230 "Duty Cycle (%)" : [f"<={ 100 * dc :0.1f} %" for dc in REF_MAX_DUTY_CYCLES ],
186231 }
187- for i , duration in enumerate (REF_MAX_SEQUENCE_TIMES ):
232+ for i , duration in enumerate (self . sequence_time ):
188233 col_name = f"<={ duration // 60 } min"
189234 data [col_name ] = [
190- MAX_VOLTAGE_BY_DUTY_CYCLE_AND_SEQUENCE_TIME [j ][i ] for j in range (len (REF_MAX_DUTY_CYCLES ))
235+ self . voltage_table [j ][i ] for j in range (len (REF_MAX_DUTY_CYCLES ))
191236 ]
192237 max_voltage = pd .DataFrame (data ).set_index ("Duty Cycle (%)" )
193238 max_voltage .Name = "Maximum Voltage (V)"
@@ -205,19 +250,21 @@ def check_solution(self, solution: Solution | Dict) -> None:
205250 if isinstance (solution , Solution ):
206251 solution = solution .to_dict ()
207252
253+ self .voltage_table = self ._resolve_voltage_chart_evt_version (self .voltage_table_selection )
254+ self .sequence_time = self ._resolve_max_sequence_time_set (self .sequence_time_selection )
208255 sequence_duty_cycle = self .get_sequence_duty_cycle (solution )
209256 duty_cycles_limits = np .array (REF_MAX_DUTY_CYCLES )
210257 if sequence_duty_cycle > duty_cycles_limits .max ():
211258 raise ValueError (f"Sequence duty cycle ({ 100 * sequence_duty_cycle :0.1f} %) exceeds maximum allowed duty cycle ({ 100 * duty_cycles_limits .max ():0.1f} %)." )
212259 duty_cycle_index = np .where (duty_cycles_limits >= sequence_duty_cycle )[0 ][0 ]
213260
214261 sequence_duration = self .get_sequence_duration (solution )
215- duration_limits = np .array (REF_MAX_SEQUENCE_TIMES )
262+ duration_limits = np .array (self . sequence_time )
216263 if sequence_duration > duration_limits .max ():
217264 raise ValueError (f"Sequence duration ({ sequence_duration :0.0f} s) exceeds maximum allowed duration ({ duration_limits .max ()} s)." )
218265 duration_index = np .where (duration_limits >= sequence_duration )[0 ][0 ]
219266
220- max_voltage = MAX_VOLTAGE_BY_DUTY_CYCLE_AND_SEQUENCE_TIME [duty_cycle_index ][duration_index ]
267+ max_voltage = self . voltage_table [duty_cycle_index ][duration_index ]
221268 if solution ['voltage' ] > max_voltage :
222269 raise ValueError (f"Voltage ({ solution ['voltage' ]:0.1f} V) exceeds maximum allowed voltage ({ max_voltage :0.1f} V) for duty cycle ({ 100 * sequence_duty_cycle :0.1f} <= { 100 * duty_cycles_limits [duty_cycle_index ]} %) and sequence time ({ sequence_duration :0.0f} <= { duration_limits [duration_index ]} s)." )
223270
0 commit comments