pre uc480 integration

This commit is contained in:
Thomas Ales [M S E]
2026-05-22 09:38:39 -05:00
parent 43e7b99512
commit a0e0151b5d
30 changed files with 12557 additions and 41 deletions
+193
View File
@@ -0,0 +1,193 @@
"""
Genesis Laser Worker Thread
Manages Genesis laser connection in a separate thread to keep the UI responsive.
Provides async querying and status monitoring via Qt signals.
"""
from PyQt6 import QtCore
from hardware.genesis_core import SerialComm, I2CProtocol, I2CDevices, LaserControl
import queue
import time
from typing import Optional
class GenesisCommand:
"""Represents a genesis laser command"""
def __init__(self, cmd_type: str, **kwargs):
self.cmd_type = cmd_type
self.params = kwargs
class GenesisWorker(QtCore.QObject):
"""
Worker object for handling Genesis laser control in a separate thread.
Signals:
connected: Emitted when laser connects successfully
disconnected: Emitted when laser disconnects
connection_failed: Emitted when connection fails (error_msg: str)
laser_info_updated: Emitted with laser status
query_completed: Emitted when a query operation completes (result: dict)
error_occurred: Emitted when an error occurs (error_msg: str)
"""
# Signals
connected = QtCore.pyqtSignal()
disconnected = QtCore.pyqtSignal()
connection_failed = QtCore.pyqtSignal(str)
laser_info_updated = QtCore.pyqtSignal(dict) # Status information
query_completed = QtCore.pyqtSignal(dict) # Query result
error_occurred = QtCore.pyqtSignal(str) # Error message
def __init__(self, port: str = "/dev/ttyUSB0", baudrate: int = 9600):
super().__init__()
self.serial_comm = SerialComm()
self.i2c_protocol = I2CProtocol(self.serial_comm)
self.i2c_devices = I2CDevices(self.i2c_protocol)
self.laser_control = LaserControl(self.i2c_devices)
self.port = port
self.baudrate = baudrate
self.is_connected = False
self.command_queue = queue.Queue()
self.running = True
# Last known laser state
self.last_laser_state = {}
# Update interval for status polling
self.last_status_update_time = 0
self.status_update_interval = 1.0 # seconds
@QtCore.pyqtSlot()
def run(self):
"""Main worker loop - processes commands from queue"""
print(f"Genesis laser worker thread started - connecting to {self.port}")
# Try to connect on startup
if self.connect():
self.connected.emit()
else:
error_msg = f"Failed to connect to Genesis laser on {self.port}"
print(error_msg)
self.connection_failed.emit(error_msg)
while self.running:
try:
# Check for commands with timeout to allow periodic status updates
try:
cmd = self.command_queue.get(timeout=0.05) # 50ms timeout
self.process_command(cmd)
except queue.Empty:
pass
# Periodically update status if connected
if self.is_connected:
current_time = time.time()
if current_time - self.last_status_update_time >= self.status_update_interval:
self.update_laser_status()
self.last_status_update_time = current_time
except Exception as e:
print(f"Error in genesis worker loop: {e}")
self.error_occurred.emit(str(e))
# Cleanup on exit
self.disconnect()
print("Genesis laser worker thread stopped")
def connect(self) -> bool:
"""Establish connection to the laser"""
try:
if self.serial_comm.connect(self.port, self.baudrate):
self.is_connected = True
print(f"Connected to Genesis laser on {self.port}")
return True
else:
print(f"Failed to open serial port {self.port}")
return False
except Exception as e:
print(f"Connection error: {e}")
return False
def disconnect(self):
"""Disconnect from the laser"""
if self.is_connected:
self.serial_comm.disconnect()
self.is_connected = False
self.disconnected.emit()
print("Disconnected from Genesis laser")
def process_command(self, cmd: GenesisCommand):
"""Process a command from the queue"""
if not self.is_connected:
self.error_occurred.emit("Laser not connected")
return
try:
if cmd.cmd_type == "query_all":
result = self.query_all_status()
self.query_completed.emit(result)
elif cmd.cmd_type == "query_current":
result = {"current": self.laser_control.get_current_actual()}
self.query_completed.emit(result)
elif cmd.cmd_type == "query_interlock":
result = {"interlock": self.laser_control.get_interlock_status()}
self.query_completed.emit(result)
elif cmd.cmd_type == "set_current":
value = cmd.params.get("value", 0)
success = self.laser_control.set_current(int(value))
self.query_completed.emit({"success": success})
elif cmd.cmd_type == "set_shutter":
state = cmd.params.get("state", False)
success = self.laser_control.set_shutter(state)
self.query_completed.emit({"success": success})
else:
self.error_occurred.emit(f"Unknown command: {cmd.cmd_type}")
except Exception as e:
self.error_occurred.emit(f"Command execution error: {e}")
def update_laser_status(self):
"""Query and emit current laser status"""
if not self.is_connected:
return
try:
status = {
"connected": True,
"current_actual": self.laser_control.get_current_actual(),
"interlock_status": self.laser_control.get_interlock_status(),
"ldd_enable_status": self.laser_control.get_ldd_enable_status(),
"psglue_in_status": self.laser_control.get_psglue_in_status(),
"psglue_out_status": self.laser_control.get_psglue_out_status(),
"head_dio_status": self.laser_control.get_head_dio_status(),
}
# Only emit if something changed
if status != self.last_laser_state:
self.last_laser_state = status
self.laser_info_updated.emit(status)
except Exception as e:
print(f"Error updating laser status: {e}")
def query_all_status(self) -> dict:
"""Query all laser status information"""
return {
"connected": True,
"current_actual": self.laser_control.get_current_actual(),
"interlock_status": self.laser_control.get_interlock_status(),
"ldd_enable_status": self.laser_control.get_ldd_enable_status(),
"psglue_in_status": self.laser_control.get_psglue_in_status(),
"psglue_out_status": self.laser_control.get_psglue_out_status(),
"head_dio_status": self.laser_control.get_head_dio_status(),
}
def queue_command(self, cmd: GenesisCommand):
"""Queue a command for execution"""
self.command_queue.put(cmd)
def stop(self):
"""Stop the worker thread"""
self.running = False