@@ -81,6 +81,7 @@ def build_ui(self):
8181 self .output_text .pack (fill = tk .BOTH , expand = True , padx = 5 , pady = 5 )
8282 for tag , opts in self .output_tags .items ():
8383 self .output_text .tag_config (tag , ** opts )
84+ self .output_text .tag_config ('command' , foreground = 'cyan' )
8485
8586 self .command_status_label = tk .Label (
8687 self .root ,
@@ -162,7 +163,9 @@ def refresh_ui(self):
162163 self .output_text .config (state = tk .NORMAL )
163164 self .output_text .delete ('1.0' , tk .END )
164165 for line in display :
165- if 'ERROR' in line :
166+ if line .startswith ('>> ' ):
167+ tag = 'command'
168+ elif 'ERROR' in line :
166169 tag = 'error'
167170 elif 'OK' in line :
168171 tag = 'ok'
@@ -190,6 +193,18 @@ def refresh_ui(self):
190193 cs_fg = 'black'
191194 self .command_status_label .config (text = self .command_result , fg = cs_fg )
192195
196+ def _attempt_reconnect (self , delay = 3 ):
197+ """Schedule a reconnection attempt without recursion."""
198+ if not self .running :
199+ return
200+ time .sleep (delay )
201+ self .output_lines = []
202+ self .output_queue .put ('[i] >> Retrying device connection...' )
203+ self .schedule_refresh ()
204+ # Use a new thread to avoid stack buildup from recursion
205+ reconnect_thread = threading .Thread (target = self .start_modem_process , daemon = True )
206+ reconnect_thread .start ()
207+
193208 def start_modem_process (self ):
194209 try :
195210 self .output_queue .put ('[i] >> Starting modem process...' )
@@ -227,57 +242,54 @@ def start_modem_process(self):
227242 if 'Local directory .' not in line :
228243 self .output_queue .put (line .strip ())
229244 self .schedule_refresh ()
230-
231- def attempt_reconnect ():
232- time .sleep (3 )
233- self .output_lines = []
234- self .output_queue .put (f'[i] >> Retrying device connection...' )
235- self .schedule_refresh ()
236- self .start_modem_process ()
237245
238- proc .stdout .close (); proc .wait ()
246+ proc .stdout .close ()
247+ proc .wait ()
239248 self .output_queue .put ('[i] >> Modem process terminated.' )
240249 self .passthrough_state = 'NO COMM'
241250 self .schedule_refresh ()
242- attempt_reconnect ( )
251+ self . _attempt_reconnect ( delay = 3 )
243252 except FileNotFoundError as e :
244253 if self .logging : self .log (line = '===== PROGRAM CRASHED =====\n ' , raw = True )
245254 self .output_queue .put (f'[i] >> Error: { e } ' )
246255 self .passthrough_state = 'ERROR'
247256 self .schedule_refresh ()
248- attempt_reconnect ( )
257+ self . _attempt_reconnect ( delay = 3 )
249258 except Exception as e :
250259 if self .logging : self .log (line = '===== PROGRAM CRASHED (Device disconnect?) =====\n ' , raw = True )
251260 self .output_queue .put (f'[i] >> Error in modem process: { e } ' )
252261 self .passthrough_state = 'NO COMM'
253262 self .schedule_refresh ()
254- time .sleep (7 )
255- self .start_modem_process ()
263+ self ._attempt_reconnect (delay = 7 )
256264
257265 def log (self , line , meta = None , raw = False ):
258266 try :
259- with open (LOG_FILE , 'a+ ' ) as f :
267+ with open (LOG_FILE , 'a' ) as f :
260268 if raw :
261269 f .write (line )
262270 else :
263271 ts = datetime .now ().strftime ('%Y-%m-%d %H:%M:%S' )
264272 f .write (f"[{ ts } ] { meta :>9} : { line .strip ()} \n " )
265- except :
273+ except OSError :
266274 pass
267275
268276 def read_cmd_file (self ):
269277 try :
270- return open (CMD_FILE ,'r' ).read ().strip ()
271- except :
278+ with open (CMD_FILE , 'r' ) as f :
279+ return f .read ().strip ()
280+ except OSError :
272281 return 'TUI-ERROR'
273282
274283 def write_cmd_file (self , command ):
275284 try :
276- with open (CMD_FILE ,'r+' ) as f :
277- if f .read ().strip () != 'READ' : return False
278- f .seek (0 ); f .write (command ); f .truncate ()
285+ with open (CMD_FILE , 'r+' ) as f :
286+ if f .read ().strip () != 'READ' :
287+ return False
288+ f .seek (0 )
289+ f .write (command )
290+ f .truncate ()
279291 return True
280- except :
292+ except OSError :
281293 return False
282294
283295 def send_interrupt_and_exit (self ):
@@ -302,6 +314,8 @@ def process_command(self):
302314 self .command_result = f'Reserved: { cmd } '
303315 elif self .passthrough_state == 'READY' and self .read_cmd_file ()== 'READ' :
304316 if self .write_cmd_file (cmd ):
317+ self .output_queue .put ('' )
318+ self .output_queue .put (f'>> { cmd } ' )
305319 self .command_result = f'Sent: { cmd } '
306320 self .passthrough_state = f'WAITING ({ cmd } )'
307321 self .history .append (cmd ); self .history_index = None
0 commit comments