Initial commit: merge nuescan, pymso, pybbd202, and pypewpewhops into scanengine-3
- Merged four separate hardware control projects into unified platform - Created unified requirements.txt with all dependencies - Added comprehensive .gitignore - Added project overview README Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Dialog controllers for nueScan application
|
||||
"""
|
||||
@@ -0,0 +1,71 @@
|
||||
"""
|
||||
Genesis Laser Settings Dialog
|
||||
Configures Genesis scanning laser parameters
|
||||
"""
|
||||
|
||||
import os
|
||||
from PyQt6 import uic
|
||||
from PyQt6.QtWidgets import QDialog
|
||||
|
||||
|
||||
class GenesisDialog(QDialog):
|
||||
"""Dialog for configuring Genesis laser settings"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
# Load UI file
|
||||
ui_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(__file__)),
|
||||
'nuescan_genesis_dialog.ui'
|
||||
)
|
||||
uic.loadUi(ui_path, self)
|
||||
|
||||
self.setWindowTitle("Genesis Laser Settings")
|
||||
|
||||
# Initialize with default values
|
||||
self._load_default_settings()
|
||||
|
||||
# Connect signals
|
||||
self._connect_signals()
|
||||
|
||||
def _connect_signals(self):
|
||||
"""Connect dialog signals"""
|
||||
# LineEdit text changed
|
||||
self.le_genesis_power_mw.textChanged.connect(self.on_power_changed)
|
||||
|
||||
# Dialog buttons are auto-connected by Qt Designer
|
||||
|
||||
def _load_default_settings(self):
|
||||
"""Load default Genesis settings"""
|
||||
self.le_genesis_power_mw.setText("100.0") # Default 100mW
|
||||
|
||||
def on_power_changed(self, text):
|
||||
"""Handle scanning power change"""
|
||||
print(f"DEBUG: Genesis power changed to: {text}")
|
||||
|
||||
def get_settings(self):
|
||||
"""
|
||||
Get current Genesis settings as a dictionary
|
||||
|
||||
Returns:
|
||||
dict: Genesis laser settings
|
||||
"""
|
||||
try:
|
||||
power_mw = float(self.le_genesis_power_mw.text())
|
||||
except ValueError:
|
||||
power_mw = 0.0
|
||||
|
||||
return {
|
||||
'power_mw': power_mw
|
||||
}
|
||||
|
||||
def set_settings(self, settings):
|
||||
"""
|
||||
Set Genesis settings from a dictionary
|
||||
|
||||
Args:
|
||||
settings (dict): Genesis laser settings
|
||||
"""
|
||||
if 'power_mw' in settings:
|
||||
self.le_genesis_power_mw.setText(str(settings['power_mw']))
|
||||
@@ -0,0 +1,169 @@
|
||||
"""
|
||||
Helios Device Settings Dialog
|
||||
Configures Helios laser parameters and COM port
|
||||
|
||||
Copyright (C) 2025 Thomas Ales
|
||||
Licensed under GNU General Public License v2.0
|
||||
"""
|
||||
|
||||
import os
|
||||
from PyQt6 import uic
|
||||
from PyQt6.QtWidgets import QDialog, QMessageBox
|
||||
from hardware.helios_driver import HeliosDriver
|
||||
|
||||
|
||||
class HeliosDialog(QDialog):
|
||||
"""Dialog for configuring Helios device settings"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
# Load UI file
|
||||
ui_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(__file__)),
|
||||
'nuescan_helios_dialog.ui'
|
||||
)
|
||||
uic.loadUi(ui_path, self)
|
||||
|
||||
self.setWindowTitle("Helios Device Settings")
|
||||
|
||||
# Initialize with default values
|
||||
self._load_default_settings()
|
||||
|
||||
# Connect signals
|
||||
self._connect_signals()
|
||||
|
||||
# Populate COM ports
|
||||
self._populate_com_ports()
|
||||
|
||||
def _connect_signals(self):
|
||||
"""Connect dialog signals"""
|
||||
# ComboBox value changed
|
||||
self.cb_helios_port.currentIndexChanged.connect(self.on_port_changed)
|
||||
|
||||
# LineEdit text changed
|
||||
self.le_helios_frequency.textChanged.connect(self.on_frequency_changed)
|
||||
self.le_helios_current.textChanged.connect(self.on_current_changed)
|
||||
|
||||
# Dialog buttons are auto-connected by Qt Designer
|
||||
|
||||
def _load_default_settings(self):
|
||||
"""Load default Helios settings"""
|
||||
self.le_helios_frequency.setText("10000") # Default 10kHz
|
||||
self.le_helios_current.setText("500") # Default 500mA
|
||||
|
||||
def _populate_com_ports(self):
|
||||
"""Populate available COM ports"""
|
||||
# Get available ports from system
|
||||
ports = HeliosDriver.list_available_ports()
|
||||
|
||||
if ports:
|
||||
self.cb_helios_port.addItems(ports)
|
||||
print(f"DEBUG: Found {len(ports)} available COM ports")
|
||||
else:
|
||||
# No ports found
|
||||
self.cb_helios_port.addItem("No ports found")
|
||||
print("WARNING: No COM ports found")
|
||||
|
||||
def refresh_com_ports(self):
|
||||
"""Refresh the COM port list"""
|
||||
current_port = self.cb_helios_port.currentText()
|
||||
self.cb_helios_port.clear()
|
||||
self._populate_com_ports()
|
||||
|
||||
# Try to restore previous selection
|
||||
index = self.cb_helios_port.findText(current_port)
|
||||
if index >= 0:
|
||||
self.cb_helios_port.setCurrentIndex(index)
|
||||
|
||||
def on_port_changed(self, index):
|
||||
"""Handle COM port selection change"""
|
||||
port = self.cb_helios_port.currentText()
|
||||
print(f"DEBUG: Helios port changed to: {port}")
|
||||
|
||||
def on_frequency_changed(self, text):
|
||||
"""Handle frequency change"""
|
||||
print(f"DEBUG: Helios frequency changed to: {text}")
|
||||
|
||||
def on_current_changed(self, text):
|
||||
"""Handle current change"""
|
||||
print(f"DEBUG: Helios current changed to: {text}")
|
||||
|
||||
def get_settings(self):
|
||||
"""
|
||||
Get current Helios settings as a dictionary
|
||||
|
||||
Validates input ranges before returning.
|
||||
|
||||
Returns:
|
||||
dict: Helios device settings, or None if validation fails
|
||||
"""
|
||||
# Validate frequency
|
||||
try:
|
||||
frequency_hz = float(self.le_helios_frequency.text())
|
||||
# Convert to period to check valid range (8000-60000 ns)
|
||||
# Valid frequencies: ~16.7 kHz to 125 kHz
|
||||
if frequency_hz < 16666 or frequency_hz > 125000:
|
||||
QMessageBox.warning(
|
||||
self, "Invalid Frequency",
|
||||
f"Frequency must be between 16.7 kHz and 125 kHz\n"
|
||||
f"(Period: 8000-60000 ns)\n\n"
|
||||
f"Entered: {frequency_hz/1000:.1f} kHz"
|
||||
)
|
||||
return None
|
||||
except ValueError:
|
||||
QMessageBox.warning(
|
||||
self, "Invalid Frequency",
|
||||
"Please enter a valid frequency value in Hz"
|
||||
)
|
||||
return None
|
||||
|
||||
# Validate current
|
||||
try:
|
||||
current_ma = float(self.le_helios_current.text())
|
||||
if current_ma < 0 or current_ma > 7000:
|
||||
QMessageBox.warning(
|
||||
self, "Invalid Current",
|
||||
f"Current must be between 0 and 7000 mA\n\n"
|
||||
f"Entered: {current_ma} mA"
|
||||
)
|
||||
return None
|
||||
except ValueError:
|
||||
QMessageBox.warning(
|
||||
self, "Invalid Current",
|
||||
"Please enter a valid current value in mA"
|
||||
)
|
||||
return None
|
||||
|
||||
# Validate COM port selection
|
||||
com_port = self.cb_helios_port.currentText()
|
||||
if not com_port or com_port == "No ports found":
|
||||
QMessageBox.warning(
|
||||
self, "No Port Selected",
|
||||
"Please select a valid COM port"
|
||||
)
|
||||
return None
|
||||
|
||||
return {
|
||||
'com_port': com_port,
|
||||
'frequency_hz': frequency_hz,
|
||||
'current_ma': current_ma
|
||||
}
|
||||
|
||||
def set_settings(self, settings):
|
||||
"""
|
||||
Set Helios settings from a dictionary
|
||||
|
||||
Args:
|
||||
settings (dict): Helios device settings
|
||||
"""
|
||||
if 'com_port' in settings:
|
||||
index = self.cb_helios_port.findText(settings['com_port'])
|
||||
if index >= 0:
|
||||
self.cb_helios_port.setCurrentIndex(index)
|
||||
|
||||
if 'frequency_hz' in settings:
|
||||
self.le_helios_frequency.setText(str(settings['frequency_hz']))
|
||||
|
||||
if 'current_ma' in settings:
|
||||
self.le_helios_current.setText(str(settings['current_ma']))
|
||||
@@ -0,0 +1,126 @@
|
||||
"""
|
||||
nueScan - Oscilloscope Dialog Controller
|
||||
Handles all UI interactions for the oscilloscope dialog
|
||||
|
||||
Copyright (C) 2025 Thomas Ales
|
||||
Licensed under GNU General Public License v2.0
|
||||
"""
|
||||
|
||||
import os
|
||||
from PyQt6 import uic
|
||||
from PyQt6.QtWidgets import QDialog, QMessageBox
|
||||
|
||||
|
||||
class OscopeDialog(QDialog):
|
||||
"""Oscope dialog for nueScan application"""
|
||||
|
||||
def __init__(self, parent, microscope):
|
||||
super().__init__(parent)
|
||||
|
||||
# Store hardware controllers
|
||||
self.microscope = microscope
|
||||
|
||||
# Load UI file
|
||||
ui_path = os.path.join(os.path.dirname(__file__), '..', 'nuescan_oscope_dialog.ui')
|
||||
uic.loadUi(ui_path, self)
|
||||
|
||||
# Set window title
|
||||
self.setWindowTitle("nueScan - Oscilloscope Settings")
|
||||
|
||||
# Connect all UI signals
|
||||
self._connect_signals()
|
||||
|
||||
# Initialize UI state
|
||||
self._initialize_ui()
|
||||
|
||||
def _connect_signals(self):
|
||||
"""Connect all UI signals to handler methods"""
|
||||
# ===== ComboBox Value Changed Handlers =====
|
||||
self.cb_set_trig_channel.currentIndexChanged.connect(self.on_trigger_channel_changed)
|
||||
self.cb_set_saw_channel.currentIndexChanged.connect(self.on_saw_channel_changed)
|
||||
self.cb_set_bias_a_ch.currentIndexChanged.connect(self.on_bias_a_channel_changed)
|
||||
self.cb_set_bias_b_ch.currentIndexChanged.connect(self.on_bias_b_channel_changed)
|
||||
|
||||
# ===== LineEdit Text Changed Handlers =====
|
||||
self.le_set_trigger_voltage.textChanged.connect(self.on_trigger_voltage_changed)
|
||||
self.le_set_sample_thresh_voltage.textChanged.connect(self.on_sample_thresh_voltage_changed)
|
||||
self.le_set_pd_trig_voltage.textChanged.connect(self.on_pd_trig_voltage_changed)
|
||||
self.le_oscope_visa_address.textChanged.connect(self.on_oscope_visa_address_changed)
|
||||
|
||||
|
||||
# ===== Button Click Handlers =====
|
||||
self.btn_test_scope_connection.clicked.connect(self.on_test_scope_connection_clicked)
|
||||
self.btn_save_scope_settings.clicked.connect(self.on_save_scope_settings_clicked)
|
||||
self.btn_cancel_scope_settings.clicked.connect(self.on_cancel_scope_settings_clicked)
|
||||
|
||||
def _initialize_ui(self):
|
||||
"""Initialize UI with default values"""
|
||||
# Populate combo boxes with dummy data
|
||||
self._populate_combo_boxes()
|
||||
|
||||
def _populate_combo_boxes(self):
|
||||
"""Populate all combo boxes with initial values"""
|
||||
# Oscilloscope channels
|
||||
channels = ["CH1", "CH2", "CH3", "CH4"]
|
||||
self.cb_set_trig_channel.addItems(channels)
|
||||
self.cb_set_saw_channel.addItems(channels)
|
||||
self.cb_set_bias_a_ch.addItems(channels)
|
||||
self.cb_set_bias_b_ch.addItems(channels)
|
||||
|
||||
|
||||
# ==================== ComboBox Change Handlers ====================
|
||||
|
||||
def on_trigger_channel_changed(self, index):
|
||||
"""Handle Phototrigger channel change"""
|
||||
channel = self.cb_set_trig_channel.currentText()
|
||||
print(f"DEBUG: Phototrigger channel changed to: {channel}")
|
||||
|
||||
def on_bias_a_channel_changed(self, index):
|
||||
"""Handle Bias A channel change"""
|
||||
channel = self.cb_set_bias_a_ch.currentText()
|
||||
print(f"DEBUG: Bias A channel changed to: {channel}")
|
||||
|
||||
def on_bias_b_channel_changed(self, index):
|
||||
"""Handle Bias B channel change"""
|
||||
channel = self.cb_set_bias_b_ch.currentText()
|
||||
print(f"DEBUG: Bias B channel changed to: {channel}")
|
||||
|
||||
def on_saw_channel_changed(self, index):
|
||||
"""Handle RF/SAW channel change"""
|
||||
channel = self.cb_set_saw_channel.currentText()
|
||||
print(f"DEBUG: RF/SAW channel changed to: {channel}")
|
||||
|
||||
|
||||
# ==================== LineEdit Text Change Handlers ====================
|
||||
|
||||
def on_pd_trig_voltage_changed(self, text):
|
||||
"""Handle PD Trigger voltage change"""
|
||||
print(f"DEBUG: PD Trigger voltage changed to: {text}")
|
||||
|
||||
def on_trigger_voltage_changed(self, text):
|
||||
"""Handle Sample Min Bias voltage change"""
|
||||
print(f"DEBUG: Sample Min Bias voltage changed to: {text}")
|
||||
|
||||
def on_sample_thresh_voltage_changed(self, text):
|
||||
"""Handle Sample Min Bias voltage change (placeholder)"""
|
||||
print(f"DEBUG: Sample threshold voltage changed to: {text}")
|
||||
|
||||
def on_oscope_visa_address_changed(self, text):
|
||||
"""Handle oscilloscope VISA address change"""
|
||||
print(f"DEBUG: Oscilloscope VISA address changed to: {text}")
|
||||
|
||||
# ==================== Button Click Handlers ====================
|
||||
|
||||
def on_test_scope_connection_clicked(self):
|
||||
"""Test the oscilloscope connection"""
|
||||
print("DEBUG: Test oscope connection clicked")
|
||||
|
||||
def on_save_scope_settings_clicked(self):
|
||||
"""Save the oscilloscope settings"""
|
||||
print("DEBUG: Save oscope settings clicked")
|
||||
self.accept()
|
||||
|
||||
def on_cancel_scope_settings_clicked(self):
|
||||
"""Cancel the oscilloscope settings changes"""
|
||||
print("DEBUG: Cancel oscope settings clicked")
|
||||
self.reject()
|
||||
@@ -0,0 +1,163 @@
|
||||
"""
|
||||
Scan Active Dialog
|
||||
Displays real-time scanning progress and status
|
||||
"""
|
||||
|
||||
import os
|
||||
from PyQt6 import uic
|
||||
from PyQt6.QtWidgets import QDialog
|
||||
from PyQt6.QtCore import QTimer
|
||||
|
||||
|
||||
class ScanActiveDialog(QDialog):
|
||||
"""Dialog for displaying active scan progress"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
# Load UI file
|
||||
ui_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(__file__)),
|
||||
'nuescan_scan_active_dialog.ui'
|
||||
)
|
||||
uic.loadUi(ui_path, self)
|
||||
|
||||
self.setWindowTitle("Scan in Progress")
|
||||
|
||||
# Make dialog modal
|
||||
self.setModal(True)
|
||||
|
||||
# Initialize state
|
||||
self.scan_cancelled = False
|
||||
|
||||
# Connect signals
|
||||
self._connect_signals()
|
||||
|
||||
# Initialize progress
|
||||
self._initialize_progress()
|
||||
|
||||
# Demo timer (for testing progress updates)
|
||||
self._demo_timer = QTimer()
|
||||
self._demo_timer.timeout.connect(self._demo_update)
|
||||
self._demo_progress = 0
|
||||
|
||||
def _connect_signals(self):
|
||||
"""Connect dialog signals"""
|
||||
self.pb_cancel_scan.clicked.connect(self.on_cancel_clicked)
|
||||
|
||||
def _initialize_progress(self):
|
||||
"""Initialize progress bars and status"""
|
||||
self.pbar_total_scan.setValue(0)
|
||||
self.pbar_this_scan.setValue(0)
|
||||
self.l_status_current_scan.setText("1")
|
||||
self.l_status_total_scans.setText("1")
|
||||
self.l_status_current_row.setText("0")
|
||||
self.l_status_total_rows.setText("0")
|
||||
self.l_est_time_done.setText("Calculating...")
|
||||
|
||||
def on_cancel_clicked(self):
|
||||
"""Handle cancel button click"""
|
||||
print("DEBUG: Scan cancelled by user")
|
||||
self.scan_cancelled = True
|
||||
self.reject()
|
||||
|
||||
# ==================== Progress Update Methods ====================
|
||||
|
||||
def update_total_progress(self, current, total):
|
||||
"""
|
||||
Update the total scan progress bar
|
||||
|
||||
Args:
|
||||
current (int): Current scan number
|
||||
total (int): Total number of scans
|
||||
"""
|
||||
if total > 0:
|
||||
percentage = int((current / total) * 100)
|
||||
self.pbar_total_scan.setValue(percentage)
|
||||
|
||||
def update_current_scan_progress(self, current, total):
|
||||
"""
|
||||
Update the current scan progress bar
|
||||
|
||||
Args:
|
||||
current (int): Current row number
|
||||
total (int): Total number of rows
|
||||
"""
|
||||
if total > 0:
|
||||
percentage = int((current / total) * 100)
|
||||
self.pbar_this_scan.setValue(percentage)
|
||||
|
||||
def update_status(self, scan_num, total_scans, row_num, total_rows, time_remaining):
|
||||
"""
|
||||
Update scan status information
|
||||
|
||||
Args:
|
||||
scan_num (int): Current scan number
|
||||
total_scans (int): Total number of scans
|
||||
row_num (int): Current row number
|
||||
total_rows (int): Total number of rows
|
||||
time_remaining (str): Estimated time remaining (formatted string)
|
||||
"""
|
||||
self.l_status_current_scan.setText(str(scan_num))
|
||||
self.l_status_total_scans.setText(str(total_scans))
|
||||
self.l_status_current_row.setText(str(row_num))
|
||||
self.l_status_total_rows.setText(str(total_rows))
|
||||
self.l_est_time_done.setText(f"{time_remaining} remaining...")
|
||||
|
||||
def start_demo_progress(self):
|
||||
"""
|
||||
Start a demo progress animation (for testing)
|
||||
Remove this method in production
|
||||
"""
|
||||
self._demo_progress = 0
|
||||
self._demo_timer.start(100) # Update every 100ms
|
||||
|
||||
def _demo_update(self):
|
||||
"""
|
||||
Demo progress update (for testing)
|
||||
Remove this method in production
|
||||
"""
|
||||
self._demo_progress += 1
|
||||
|
||||
# Simulate scan progress
|
||||
total_scans = 5
|
||||
rows_per_scan = 100
|
||||
total_steps = total_scans * rows_per_scan
|
||||
|
||||
current_scan = (self._demo_progress // rows_per_scan) + 1
|
||||
current_row = (self._demo_progress % rows_per_scan)
|
||||
|
||||
if current_scan > total_scans:
|
||||
self._demo_timer.stop()
|
||||
self.accept()
|
||||
return
|
||||
|
||||
# Update progress
|
||||
self.update_total_progress(current_scan - 1, total_scans)
|
||||
self.update_current_scan_progress(current_row, rows_per_scan)
|
||||
|
||||
# Calculate time remaining (demo)
|
||||
remaining_steps = total_steps - self._demo_progress
|
||||
seconds_remaining = remaining_steps * 0.1 # 0.1s per step
|
||||
hours = int(seconds_remaining // 3600)
|
||||
minutes = int((seconds_remaining % 3600) // 60)
|
||||
seconds = int(seconds_remaining % 60)
|
||||
|
||||
time_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
||||
|
||||
self.update_status(
|
||||
current_scan,
|
||||
total_scans,
|
||||
current_row,
|
||||
rows_per_scan,
|
||||
time_str
|
||||
)
|
||||
|
||||
def is_cancelled(self):
|
||||
"""
|
||||
Check if scan was cancelled
|
||||
|
||||
Returns:
|
||||
bool: True if cancelled, False otherwise
|
||||
"""
|
||||
return self.scan_cancelled
|
||||
@@ -0,0 +1,101 @@
|
||||
"""
|
||||
nueScan - Status Dialog Controller
|
||||
Handles all UI interactions for the status dialog
|
||||
|
||||
Copyright (C) 2025 Thomas Ales
|
||||
Licensed under GNU General Public License v2.0
|
||||
"""
|
||||
|
||||
import os
|
||||
from PyQt6 import uic
|
||||
from PyQt6.QtWidgets import QDialog
|
||||
|
||||
|
||||
class StatusDialog(QDialog):
|
||||
"""Status dialog for nueScan application"""
|
||||
|
||||
def __init__(self, parent, thorlabs_stage, t3r_device, microscope):
|
||||
super().__init__(parent)
|
||||
|
||||
# Store hardware controllers
|
||||
self.thorlabs_stage = thorlabs_stage
|
||||
self.t3r_device = t3r_device
|
||||
self.microscope = microscope
|
||||
|
||||
# Load UI file
|
||||
ui_path = os.path.join(os.path.dirname(__file__), '..', 'nuescan_status_dialog.ui')
|
||||
uic.loadUi(ui_path, self)
|
||||
|
||||
# Set window title
|
||||
self.setWindowTitle("nueScan - Status Indicators")
|
||||
|
||||
def update_all_status(self):
|
||||
"""Update all status labels with current hardware states"""
|
||||
self._update_stage_status()
|
||||
self._update_t3r_status()
|
||||
self._update_microscope_status()
|
||||
self._update_transfer_system_status()
|
||||
|
||||
def _update_stage_status(self):
|
||||
"""Update ThorLabs stage status indicators"""
|
||||
status = self.thorlabs_stage.get_status()
|
||||
|
||||
self.l_is_mls_connected.setText("Yes" if status['connected'] else "No")
|
||||
self.l_is_mls_x_home.setText("Yes" if status['x_homed'] else "No")
|
||||
self.l_is_mls_y_home.setText("Yes" if status['y_homed'] else "No")
|
||||
self.l_is_mls_ready.setText("Yes" if status['ready'] else "No")
|
||||
self.l_is_mls_scanning.setText("Yes" if status['scanning'] else "No")
|
||||
|
||||
def _update_t3r_status(self):
|
||||
"""Update T3R device status indicators"""
|
||||
status = self.t3r_device.get_status()
|
||||
|
||||
self.l_is_t3r_connected.setText("Yes" if status['connected'] else "No")
|
||||
self.l_is_t3r_homed.setText("Yes" if status['homed'] else "No")
|
||||
self.l_is_t3r_ready.setText("Yes" if status['ready'] else "No")
|
||||
|
||||
def _update_microscope_status(self):
|
||||
"""Update microscope (Genesis/Helios) status indicators"""
|
||||
status = self.microscope.get_status()
|
||||
|
||||
# Helios status
|
||||
self.l_is_helios_ready.setText("Yes" if status['helios_ready'] else "No")
|
||||
self.l_is_helios_interlocked.setText("Yes" if status['helios_interlocked'] else "No")
|
||||
|
||||
# Genesis status
|
||||
self.l_is_genesis_ready.setText("Yes" if status['genesis_ready'] else "No")
|
||||
self.l_is_genesis_interlocked.setText("Yes" if status['genesis_interlocked'] else "No")
|
||||
|
||||
def _update_transfer_system_status(self):
|
||||
"""Update Robo-met.3D transfer system status indicators"""
|
||||
# Stub implementation - would read from actual I/O
|
||||
# These represent digital I/O states
|
||||
io_states = self._read_transfer_io_states()
|
||||
|
||||
# SRAS outputs
|
||||
self.l_sras_ok.setText("High (1)" if io_states['sras_ok'] else "Low (0)")
|
||||
self.l_sras_ctl.setText("High (1)" if io_states['sras_ctl'] else "Low (0)")
|
||||
self.l_sras_done.setText("High (1)" if io_states['sras_done'] else "Low (0)")
|
||||
self.l_sras_error.setText("High (1)" if io_states['sras_error'] else "Low (0)")
|
||||
|
||||
# R3D inputs
|
||||
self.l_r3d_estop_ok.setText("High (1)" if io_states['r3d_estop'] else "Low (0)")
|
||||
self.l_r3d_rtl.setText("High (1)" if io_states['r3d_ready_to_load'] else "Low (0)")
|
||||
self.l_r3d_rts.setText("High (1)" if io_states['r3d_ready_to_start'] else "Low (0)")
|
||||
self.l_r3d_spare.setText("High (1)" if io_states['r3d_spare'] else "Low (0)")
|
||||
|
||||
def _read_transfer_io_states(self):
|
||||
"""
|
||||
Stub method to read transfer system I/O states
|
||||
In production, this would read from actual hardware I/O
|
||||
"""
|
||||
return {
|
||||
'sras_ok': False,
|
||||
'sras_ctl': False,
|
||||
'sras_done': False,
|
||||
'sras_error': False,
|
||||
'r3d_estop': True, # Active low, so True = OK
|
||||
'r3d_ready_to_load': False,
|
||||
'r3d_ready_to_start': False,
|
||||
'r3d_spare': False
|
||||
}
|
||||
Reference in New Issue
Block a user