pre uc480 integration
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user