MainCode/adalm1000_logger.py aktualisiert
still not ready D
This commit is contained in:
parent
411528cdcd
commit
15e6856e76
@ -7,6 +7,7 @@ import traceback
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib
|
import matplotlib
|
||||||
|
import subprocess
|
||||||
matplotlib.use('Qt5Agg')
|
matplotlib.use('Qt5Agg')
|
||||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||||
from matplotlib.figure import Figure
|
from matplotlib.figure import Figure
|
||||||
@ -34,6 +35,7 @@ class DeviceManager:
|
|||||||
self._last_log_time = 0
|
self._last_log_time = 0
|
||||||
self.log_dir = os.path.expanduser("~/adalm1000/logs")
|
self.log_dir = os.path.expanduser("~/adalm1000/logs")
|
||||||
os.makedirs(self.log_dir, exist_ok=True)
|
os.makedirs(self.log_dir, exist_ok=True)
|
||||||
|
self.session = None
|
||||||
|
|
||||||
# Datenpuffer
|
# Datenpuffer
|
||||||
max_data_points = 36000
|
max_data_points = 36000
|
||||||
@ -52,6 +54,7 @@ class DeviceManager:
|
|||||||
self.cycle_count = 0
|
self.cycle_count = 0
|
||||||
self.test_phase = "Idle"
|
self.test_phase = "Idle"
|
||||||
self.start_time = time.time()
|
self.start_time = time.time()
|
||||||
|
self.plot_mutex = threading.Lock()
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
self.current_cycle_file = None
|
self.current_cycle_file = None
|
||||||
@ -78,40 +81,110 @@ class DeviceManager:
|
|||||||
|
|
||||||
if self.consecutive_read_errors >= self.max_consecutive_errors:
|
if self.consecutive_read_errors >= self.max_consecutive_errors:
|
||||||
try:
|
try:
|
||||||
print("Attempting device recovery...")
|
print(f"Attempting device recovery (errors: {self.consecutive_read_errors})...")
|
||||||
|
|
||||||
# 1. First try soft reset
|
# 1. First try soft reset
|
||||||
try:
|
try:
|
||||||
if hasattr(self.dev, 'reset'):
|
if hasattr(self.dev, 'reset'):
|
||||||
|
print("Attempting soft reset...")
|
||||||
self.dev.reset()
|
self.dev.reset()
|
||||||
time.sleep(0.5)
|
time.sleep(1.5) # Increased delay for reset to complete
|
||||||
return True
|
|
||||||
|
# Verify reset worked
|
||||||
|
try:
|
||||||
|
samples = self.dev.read(1, 500, True)
|
||||||
|
if samples:
|
||||||
|
self.consecutive_read_errors = 0
|
||||||
|
print("Soft reset successful")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Verification after soft reset failed: {e}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Soft reset failed: {e}")
|
print(f"Soft reset failed: {e}")
|
||||||
|
|
||||||
# 2. Full reinitialization
|
# 2. Full reinitialization with USB reset
|
||||||
global_session = pysmu.Session()
|
print("Attempting full USB reset...")
|
||||||
devices = global_session.devices
|
try:
|
||||||
|
# Close existing session cleanly
|
||||||
|
if hasattr(self, 'session') and self.session:
|
||||||
|
try:
|
||||||
|
print("Ending existing session...")
|
||||||
|
self.session.end()
|
||||||
|
time.sleep(0.5)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error ending session: {e}")
|
||||||
|
|
||||||
if not devices:
|
# Add delay and attempt USB reset
|
||||||
print("No devices found after rescan")
|
time.sleep(2.0) # Longer delay for USB to settle
|
||||||
|
|
||||||
|
# Try multiple times to scan for devices
|
||||||
|
for attempt in range(3):
|
||||||
|
try:
|
||||||
|
print(f"Scan attempt {attempt + 1}/3...")
|
||||||
|
new_session = pysmu.Session(ignore_dataflow=True, queue_size=10000)
|
||||||
|
devices = new_session.scan()
|
||||||
|
|
||||||
|
if not devices:
|
||||||
|
print(f"No devices found on attempt {attempt+1}/3")
|
||||||
|
time.sleep(1.0)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Find our device by serial
|
||||||
|
for new_dev in devices:
|
||||||
|
if new_dev.serial == self.serial:
|
||||||
|
print(f"Found device {self.serial} on attempt {attempt+1}")
|
||||||
|
self.dev = new_dev
|
||||||
|
self.consecutive_read_errors = 0
|
||||||
|
self.session = new_session # Update session reference
|
||||||
|
|
||||||
|
# Restart measurement thread
|
||||||
|
if hasattr(self, 'measurement_thread'):
|
||||||
|
try:
|
||||||
|
self.measurement_thread.stop()
|
||||||
|
time.sleep(0.5)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.start_measurement(self.interval)
|
||||||
|
|
||||||
|
print("Device reinitialized successfully")
|
||||||
|
return True
|
||||||
|
|
||||||
|
print(f"Original device not found on attempt {attempt+1}")
|
||||||
|
time.sleep(1.0)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Scan attempt {attempt+1} failed: {e}")
|
||||||
|
time.sleep(1.0)
|
||||||
|
|
||||||
|
print("Failed to find original device after 3 attempts")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Find our device by serial
|
except Exception as e:
|
||||||
for new_dev in devices:
|
print(f"Full reinitialization failed: {e}")
|
||||||
if new_dev.serial == self.serial:
|
return False
|
||||||
self.dev = new_dev
|
|
||||||
self.consecutive_read_errors = 0
|
|
||||||
print("Device reinitialized successfully")
|
|
||||||
return True
|
|
||||||
|
|
||||||
print("Original device not found after rescan")
|
# 3. Final fallback - try USB reset command
|
||||||
return False
|
try:
|
||||||
|
print("Attempting USB port reset...")
|
||||||
|
import subprocess
|
||||||
|
# ADALM1000 USB IDs
|
||||||
|
result = subprocess.run(['usbreset', '064b:784c'],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
|
if result.returncode == 0:
|
||||||
|
print("USB reset command executed, waiting 3 seconds...")
|
||||||
|
time.sleep(3.0)
|
||||||
|
return self.handle_read_error(0) # Retry with counter reset
|
||||||
|
else:
|
||||||
|
print("USB reset failed - command not found or permission denied")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"USB reset command failed: {e}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Device recovery failed: {e}")
|
print(f"Device recovery failed: {e}")
|
||||||
return False
|
return False
|
||||||
return True
|
|
||||||
|
return True # Not enough errors yet to trigger recovery
|
||||||
|
|
||||||
def start_measurement(self, interval=0.1):
|
def start_measurement(self, interval=0.1):
|
||||||
self.stop_measurement() # Ensure any existing thread is stopped
|
self.stop_measurement() # Ensure any existing thread is stopped
|
||||||
@ -226,7 +299,7 @@ class MeasurementThread(QThread):
|
|||||||
current = np.mean(self.current_window)
|
current = np.mean(self.current_window)
|
||||||
|
|
||||||
# Validate measurements
|
# Validate measurements
|
||||||
if not (0.0 <= voltage <= 5.0):
|
if not (-0.2 <= voltage <= 5.0):
|
||||||
raise ValueError(f"Voltage out of range: {voltage:.4f}V")
|
raise ValueError(f"Voltage out of range: {voltage:.4f}V")
|
||||||
if not (-0.25 <= current <= 0.25):
|
if not (-0.25 <= current <= 0.25):
|
||||||
raise ValueError(f"Current out of range: {current:.4f}A")
|
raise ValueError(f"Current out of range: {current:.4f}A")
|
||||||
@ -470,10 +543,11 @@ class DischargeWorker(QObject):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Update parent's data for logging/display
|
# Update parent's data for logging/display
|
||||||
with self.parent.plot_mutex:
|
if self.parent.active_device:
|
||||||
if len(self.parent.voltage_data) > 0:
|
with self.parent.active_device.plot_mutex:
|
||||||
self.parent.voltage_data[-1] = voltage
|
if self.parent.active_device.voltage_data:
|
||||||
self.parent.current_data[-1] = current
|
self.parent.active_device.voltage_data[-1] = voltage
|
||||||
|
self.parent.active_device.current_data[-1] = current
|
||||||
|
|
||||||
if voltage <= self.discharge_cutoff:
|
if voltage <= self.discharge_cutoff:
|
||||||
break
|
break
|
||||||
@ -543,10 +617,11 @@ class ChargeWorker(QObject):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Update parent's data for logging/display
|
# Update parent's data for logging/display
|
||||||
with self.parent.plot_mutex:
|
if self.parent.active_device:
|
||||||
if len(self.parent.voltage_data) > 0:
|
with self.parent.active_device.plot_mutex:
|
||||||
self.parent.voltage_data[-1] = voltage
|
if self.parent.active_device.voltage_data:
|
||||||
self.parent.current_data[-1] = current
|
self.parent.active_device.voltage_data[-1] = voltage
|
||||||
|
self.parent.active_device.current_data[-1] = current
|
||||||
|
|
||||||
if voltage >= self.charge_cutoff:
|
if voltage >= self.charge_cutoff:
|
||||||
break
|
break
|
||||||
@ -919,9 +994,14 @@ class BatteryTester(QMainWindow):
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
min-height: 28px;
|
min-height: 28px;
|
||||||
background-color: {self.accent_color};
|
background-color: {self.accent_color};
|
||||||
|
color: {self.fg_color};
|
||||||
}}
|
}}
|
||||||
QPushButton:checked {{
|
QPushButton:checked {{
|
||||||
background-color: {self.warning_color};
|
background-color: {self.warning_color} !important;
|
||||||
|
color: {self.fg_color} !important;
|
||||||
|
}}
|
||||||
|
QPushButton:disabled {{
|
||||||
|
background-color: #4C566A;
|
||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -973,6 +1053,49 @@ class BatteryTester(QMainWindow):
|
|||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
def apply_button_style(self):
|
||||||
|
"""Apply consistent button styling based on current state"""
|
||||||
|
if self.toggle_button.isChecked():
|
||||||
|
# Stop state
|
||||||
|
self.toggle_button.setStyleSheet(f"""
|
||||||
|
QPushButton {{
|
||||||
|
background-color: {self.warning_color};
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
min-height: 28px;
|
||||||
|
}}
|
||||||
|
QPushButton:hover {{
|
||||||
|
background-color: #{self.darker_color(self.warning_color)};
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
# Start state
|
||||||
|
self.toggle_button.setStyleSheet(f"""
|
||||||
|
QPushButton {{
|
||||||
|
background-color: {self.accent_color};
|
||||||
|
color: {self.fg_color};
|
||||||
|
font-weight: bold;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
min-height: 28px;
|
||||||
|
}}
|
||||||
|
QPushButton:hover {{
|
||||||
|
background-color: #{self.darker_color(self.accent_color)};
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
|
||||||
|
def darker_color(self, hex_color):
|
||||||
|
"""Helper to generate a darker shade for hover effects"""
|
||||||
|
if not hex_color.startswith('#'):
|
||||||
|
hex_color = '#' + hex_color
|
||||||
|
rgb = [int(hex_color[i:i+2], 16) for i in (1, 3, 5)]
|
||||||
|
darker = [max(0, c - 40) for c in rgb]
|
||||||
|
return ''.join([f"{c:02x}" for c in darker])
|
||||||
|
|
||||||
def toggle_global_recording(self):
|
def toggle_global_recording(self):
|
||||||
"""Toggle recording for all connected devices simultaneously"""
|
"""Toggle recording for all connected devices simultaneously"""
|
||||||
if not hasattr(self, 'global_recording'):
|
if not hasattr(self, 'global_recording'):
|
||||||
@ -1006,15 +1129,23 @@ class BatteryTester(QMainWindow):
|
|||||||
self.record_button.setStyleSheet(f"background-color: {self.success_color};")
|
self.record_button.setStyleSheet(f"background-color: {self.success_color};")
|
||||||
self.status_bar.showMessage("Recording stopped for all devices")
|
self.status_bar.showMessage("Recording stopped for all devices")
|
||||||
|
|
||||||
|
def safe_execute(func):
|
||||||
|
"""Decorator to catch and log exceptions in Qt event handlers"""
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
try:
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error in {func.__name__}: {str(e)}")
|
||||||
|
traceback.print_exc()
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
@safe_execute
|
||||||
def toggle_test(self):
|
def toggle_test(self):
|
||||||
"""Toggle between start and stop based on button state"""
|
|
||||||
if self.toggle_button.isChecked():
|
if self.toggle_button.isChecked():
|
||||||
# Button shows "STOP" - run start logic
|
self.apply_button_style() # Add this line
|
||||||
self.toggle_button.setText("STOP")
|
|
||||||
self.start_test()
|
self.start_test()
|
||||||
else:
|
else:
|
||||||
# Button shows "START" - run stop logic
|
self.apply_button_style() # Add this line
|
||||||
self.toggle_button.setText("START")
|
|
||||||
self.stop_test()
|
self.stop_test()
|
||||||
|
|
||||||
def change_mode(self, mode_name):
|
def change_mode(self, mode_name):
|
||||||
@ -1056,6 +1187,7 @@ class BatteryTester(QMainWindow):
|
|||||||
# Reset button state
|
# Reset button state
|
||||||
self.toggle_button.setChecked(False)
|
self.toggle_button.setChecked(False)
|
||||||
self.toggle_button.setEnabled(True)
|
self.toggle_button.setEnabled(True)
|
||||||
|
self.apply_button_style()
|
||||||
|
|
||||||
# Reset measurement state and zero the time
|
# Reset measurement state and zero the time
|
||||||
if self.active_device:
|
if self.active_device:
|
||||||
@ -1071,7 +1203,7 @@ class BatteryTester(QMainWindow):
|
|||||||
self.energy_label.setText("0.0000")
|
self.energy_label.setText("0.0000")
|
||||||
self.cycle_label.setText("0")
|
self.cycle_label.setText("0")
|
||||||
self.phase_label.setText("Idle")
|
self.phase_label.setText("Idle")
|
||||||
self.time_label.setText("00:00:00")
|
#self.time_label.setText("00:00:00")
|
||||||
|
|
||||||
# Reset plot
|
# Reset plot
|
||||||
self.reset_plot()
|
self.reset_plot()
|
||||||
@ -1090,6 +1222,9 @@ class BatteryTester(QMainWindow):
|
|||||||
else:
|
else:
|
||||||
self.record_button.setVisible(False)
|
self.record_button.setVisible(False)
|
||||||
|
|
||||||
|
self.apply_button_style()
|
||||||
|
self.status_bar.showMessage(f"Mode changed to {mode_name}")
|
||||||
|
|
||||||
def reset_test(self):
|
def reset_test(self):
|
||||||
if not self.active_device:
|
if not self.active_device:
|
||||||
return
|
return
|
||||||
@ -1399,6 +1534,7 @@ class BatteryTester(QMainWindow):
|
|||||||
# Start measurement only AFTER connecting signals
|
# Start measurement only AFTER connecting signals
|
||||||
if not self.measurement_thread.isRunning():
|
if not self.measurement_thread.isRunning():
|
||||||
self.active_device.start_measurement(self.interval)
|
self.active_device.start_measurement(self.interval)
|
||||||
|
print("Measurement thread running?", self.measurement_thread.isRunning())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error connecting to new device: {e}")
|
print(f"Error connecting to new device: {e}")
|
||||||
return
|
return
|
||||||
@ -1441,6 +1577,7 @@ class BatteryTester(QMainWindow):
|
|||||||
self.cycle_label.setText(str(dev.cycle_count))
|
self.cycle_label.setText(str(dev.cycle_count))
|
||||||
self.phase_label.setText(dev.test_phase)
|
self.phase_label.setText(dev.test_phase)
|
||||||
|
|
||||||
|
@safe_execute
|
||||||
@pyqtSlot(float, float, float)
|
@pyqtSlot(float, float, float)
|
||||||
def update_measurements(self, voltage, current, current_time):
|
def update_measurements(self, voltage, current, current_time):
|
||||||
if not self.active_device:
|
if not self.active_device:
|
||||||
@ -1552,6 +1689,12 @@ class BatteryTester(QMainWindow):
|
|||||||
self.capacity_label.setText(f"{dev.capacity_ah:.4f}")
|
self.capacity_label.setText(f"{dev.capacity_ah:.4f}")
|
||||||
self.energy_label.setText(f"{dev.energy:.4f}")
|
self.energy_label.setText(f"{dev.energy:.4f}")
|
||||||
|
|
||||||
|
# Update elapsed-time display
|
||||||
|
if self.active_device and self.active_device.time_data:
|
||||||
|
elapsed = self.active_device.time_data[-1]
|
||||||
|
self.time_label.setText(self.format_time(elapsed))
|
||||||
|
|
||||||
|
@safe_execute
|
||||||
def start_test(self):
|
def start_test(self):
|
||||||
"""Start the selected test mode using the active device"""
|
"""Start the selected test mode using the active device"""
|
||||||
if not self.active_device:
|
if not self.active_device:
|
||||||
@ -1574,6 +1717,7 @@ class BatteryTester(QMainWindow):
|
|||||||
dev_manager.measurement_thread.current_window.clear()
|
dev_manager.measurement_thread.current_window.clear()
|
||||||
with dev_manager.measurement_thread.measurement_queue.mutex:
|
with dev_manager.measurement_thread.measurement_queue.mutex:
|
||||||
dev_manager.measurement_thread.measurement_queue.queue.clear()
|
dev_manager.measurement_thread.measurement_queue.queue.clear()
|
||||||
|
self.time_label.setText("00:00:00")
|
||||||
|
|
||||||
# Reset data buffers
|
# Reset data buffers
|
||||||
dev_manager.time_data.clear()
|
dev_manager.time_data.clear()
|
||||||
@ -1613,6 +1757,7 @@ class BatteryTester(QMainWindow):
|
|||||||
# Update UI
|
# Update UI
|
||||||
self.phase_label.setText(dev_manager.test_phase)
|
self.phase_label.setText(dev_manager.test_phase)
|
||||||
self.toggle_button.setText("STOP")
|
self.toggle_button.setText("STOP")
|
||||||
|
self.apply_button_style()
|
||||||
|
|
||||||
# Get parameters from UI
|
# Get parameters from UI
|
||||||
try:
|
try:
|
||||||
@ -1801,6 +1946,7 @@ class BatteryTester(QMainWindow):
|
|||||||
|
|
||||||
self.toggle_button.setChecked(True)
|
self.toggle_button.setChecked(True)
|
||||||
self.toggle_button.setText("STOP")
|
self.toggle_button.setText("STOP")
|
||||||
|
self.apply_button_style()
|
||||||
self.status_bar.showMessage(f"Cycle test started | Current: {test_current:.4f}A")
|
self.status_bar.showMessage(f"Cycle test started | Current: {test_current:.4f}A")
|
||||||
|
|
||||||
# Create log file
|
# Create log file
|
||||||
@ -1837,6 +1983,7 @@ class BatteryTester(QMainWindow):
|
|||||||
# Ensure buttons are in correct state if error occurs
|
# Ensure buttons are in correct state if error occurs
|
||||||
self.toggle_button.setChecked(False)
|
self.toggle_button.setChecked(False)
|
||||||
self.toggle_button.setText("START")
|
self.toggle_button.setText("START")
|
||||||
|
self.apply_button_style()
|
||||||
self.toggle_button.setEnabled(True)
|
self.toggle_button.setEnabled(True)
|
||||||
|
|
||||||
def start_discharge_test(self):
|
def start_discharge_test(self):
|
||||||
@ -1911,6 +2058,7 @@ class BatteryTester(QMainWindow):
|
|||||||
|
|
||||||
self.toggle_button.setChecked(True)
|
self.toggle_button.setChecked(True)
|
||||||
self.toggle_button.setText("STOP")
|
self.toggle_button.setText("STOP")
|
||||||
|
self.apply_button_style()
|
||||||
self.status_bar.showMessage(f"Discharge started | Current: {test_current:.4f}A")
|
self.status_bar.showMessage(f"Discharge started | Current: {test_current:.4f}A")
|
||||||
|
|
||||||
# Create log file
|
# Create log file
|
||||||
@ -1943,6 +2091,7 @@ class BatteryTester(QMainWindow):
|
|||||||
# Ensure buttons are in correct state if error occurs
|
# Ensure buttons are in correct state if error occurs
|
||||||
self.toggle_button.setChecked(False)
|
self.toggle_button.setChecked(False)
|
||||||
self.toggle_button.setText("START")
|
self.toggle_button.setText("START")
|
||||||
|
self.apply_button_style()
|
||||||
self.toggle_button.setEnabled(True)
|
self.toggle_button.setEnabled(True)
|
||||||
|
|
||||||
def start_charge_test(self):
|
def start_charge_test(self):
|
||||||
@ -2017,6 +2166,7 @@ class BatteryTester(QMainWindow):
|
|||||||
|
|
||||||
self.toggle_button.setChecked(True)
|
self.toggle_button.setChecked(True)
|
||||||
self.toggle_button.setText("STOP")
|
self.toggle_button.setText("STOP")
|
||||||
|
self.apply_button_style()
|
||||||
self.status_bar.showMessage(f"Charge started @ {test_current:.3f}A to {self.charge_cutoff}V")
|
self.status_bar.showMessage(f"Charge started @ {test_current:.3f}A to {self.charge_cutoff}V")
|
||||||
|
|
||||||
# Create log file
|
# Create log file
|
||||||
@ -2048,6 +2198,7 @@ class BatteryTester(QMainWindow):
|
|||||||
QMessageBox.critical(self, "Error", str(e))
|
QMessageBox.critical(self, "Error", str(e))
|
||||||
self.toggle_button.setChecked(False)
|
self.toggle_button.setChecked(False)
|
||||||
self.toggle_button.setText("START")
|
self.toggle_button.setText("START")
|
||||||
|
self.apply_button_style()
|
||||||
self.toggle_button.setEnabled(True)
|
self.toggle_button.setEnabled(True)
|
||||||
|
|
||||||
def start_live_monitoring(self, device):
|
def start_live_monitoring(self, device):
|
||||||
@ -2164,6 +2315,7 @@ class BatteryTester(QMainWindow):
|
|||||||
seconds = int(seconds % 60)
|
seconds = int(seconds % 60)
|
||||||
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
||||||
|
|
||||||
|
@safe_execute
|
||||||
def stop_test(self):
|
def stop_test(self):
|
||||||
"""Request immediate stop with proper visual feedback"""
|
"""Request immediate stop with proper visual feedback"""
|
||||||
# Immediate red button feedback
|
# Immediate red button feedback
|
||||||
@ -2243,6 +2395,7 @@ class BatteryTester(QMainWindow):
|
|||||||
|
|
||||||
self.toggle_button.setChecked(False)
|
self.toggle_button.setChecked(False)
|
||||||
self.toggle_button.setText(text)
|
self.toggle_button.setText(text)
|
||||||
|
self.apply_button_style()
|
||||||
self.toggle_button.setStyleSheet(f"""
|
self.toggle_button.setStyleSheet(f"""
|
||||||
QPushButton {{
|
QPushButton {{
|
||||||
background-color: {self.status_colors["active"]};
|
background-color: {self.status_colors["active"]};
|
||||||
@ -2279,12 +2432,23 @@ class BatteryTester(QMainWindow):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
"""Ensure all log files are properly closed"""
|
"""Ensure clean shutdown"""
|
||||||
if hasattr(self, 'global_recording') and self.global_recording:
|
self.stop_test()
|
||||||
self.toggle_global_recording() # This will stop all recordings
|
|
||||||
|
|
||||||
# Additional cleanup if needed
|
# Stop all timers
|
||||||
super().closeEvent(event)
|
self.status_timer.stop()
|
||||||
|
|
||||||
|
# Close all log files
|
||||||
|
for device in self.devices.values():
|
||||||
|
if device.is_recording:
|
||||||
|
self.finalize_device_log_file(device)
|
||||||
|
|
||||||
|
# Clean up threads
|
||||||
|
if hasattr(self, 'measurement_thread') and self.measurement_thread:
|
||||||
|
self.measurement_thread.stop()
|
||||||
|
self.measurement_thread.wait(1000)
|
||||||
|
|
||||||
|
event.accept()
|
||||||
|
|
||||||
def reset_test_data(self):
|
def reset_test_data(self):
|
||||||
if not self.active_device:
|
if not self.active_device:
|
||||||
@ -2311,7 +2475,7 @@ class BatteryTester(QMainWindow):
|
|||||||
# Reset UI displays
|
# Reset UI displays
|
||||||
self.voltage_label.setText("0.000")
|
self.voltage_label.setText("0.000")
|
||||||
self.current_label.setText("0.000")
|
self.current_label.setText("0.000")
|
||||||
self.time_label.setText("00:00:00")
|
#self.time_label.setText("00:00:00")
|
||||||
self.capacity_label.setText("0.0000")
|
self.capacity_label.setText("0.0000")
|
||||||
self.energy_label.setText("0.0000")
|
self.energy_label.setText("0.0000")
|
||||||
self.phase_label.setText("Idle")
|
self.phase_label.setText("Idle")
|
||||||
@ -2435,7 +2599,10 @@ class BatteryTester(QMainWindow):
|
|||||||
self.request_stop = False
|
self.request_stop = False
|
||||||
self.toggle_button.setChecked(False)
|
self.toggle_button.setChecked(False)
|
||||||
self.toggle_button.setText("START")
|
self.toggle_button.setText("START")
|
||||||
|
self.apply_button_style()
|
||||||
self.toggle_button.setEnabled(True)
|
self.toggle_button.setEnabled(True)
|
||||||
|
self.apply_button_style() # Add this line
|
||||||
|
self.test_running = False
|
||||||
|
|
||||||
# 8. Show completion message if test wasn't stopped by user
|
# 8. Show completion message if test wasn't stopped by user
|
||||||
if not self.request_stop:
|
if not self.request_stop:
|
||||||
@ -2495,6 +2662,7 @@ class BatteryTester(QMainWindow):
|
|||||||
# Ensure we don't leave the UI in a locked state
|
# Ensure we don't leave the UI in a locked state
|
||||||
self.toggle_button.setChecked(False)
|
self.toggle_button.setChecked(False)
|
||||||
self.toggle_button.setText("START")
|
self.toggle_button.setText("START")
|
||||||
|
self.apply_button_style()
|
||||||
self.toggle_button.setEnabled(True)
|
self.toggle_button.setEnabled(True)
|
||||||
self.status_bar.showMessage("Error during test finalization")
|
self.status_bar.showMessage("Error during test finalization")
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user