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,387 @@
|
||||
"""
|
||||
Microscope Controller
|
||||
Handles communication with Genesis and Helios microscope/laser systems
|
||||
|
||||
Genesis: Laser scanning microscope system (stub)
|
||||
Helios: Laser control system with frequency and current control (full implementation)
|
||||
Both systems communicate via USB/Serial interfaces
|
||||
|
||||
Copyright (C) 2025 Thomas Ales
|
||||
Licensed under GNU General Public License v2.0
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Dict, Optional
|
||||
from hardware.helios_driver import HeliosDriver, PulseMode
|
||||
|
||||
|
||||
class MicroscopeController:
|
||||
"""
|
||||
Controller for Genesis and Helios microscope systems
|
||||
|
||||
Provides methods for:
|
||||
- System connection and initialization
|
||||
- Interlock status monitoring
|
||||
- Parameter configuration
|
||||
- Safety checks
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize microscope controller"""
|
||||
# Genesis state (stub)
|
||||
self._genesis_connected = False
|
||||
self._genesis_ready = False
|
||||
self._genesis_interlocked = False
|
||||
self._genesis_power_mw = 0.0
|
||||
|
||||
# Helios driver (full implementation)
|
||||
self._helios_driver = HeliosDriver()
|
||||
self._helios_port = None
|
||||
|
||||
# System interlock (master safety)
|
||||
self._system_interlocked = False
|
||||
|
||||
print("INFO: Microscope controller initialized")
|
||||
print(" - Genesis: Stub implementation")
|
||||
print(" - Helios: Full RS-232 driver")
|
||||
|
||||
# ==================== Genesis Methods ====================
|
||||
|
||||
def connect_genesis(self) -> bool:
|
||||
"""
|
||||
Connect to Genesis laser scanning microscope
|
||||
|
||||
Returns:
|
||||
bool: True if connection successful
|
||||
"""
|
||||
print("DEBUG: Connecting to Genesis microscope")
|
||||
|
||||
# Stub implementation
|
||||
time.sleep(0.1)
|
||||
|
||||
self._genesis_connected = True
|
||||
self._genesis_ready = True
|
||||
self._genesis_interlocked = True # Assume interlocks OK
|
||||
|
||||
print("INFO: Genesis microscope connected")
|
||||
return True
|
||||
|
||||
def disconnect_genesis(self) -> bool:
|
||||
"""
|
||||
Disconnect from Genesis microscope
|
||||
|
||||
Returns:
|
||||
bool: True if disconnection successful
|
||||
"""
|
||||
print("DEBUG: Disconnecting from Genesis microscope")
|
||||
|
||||
self._genesis_connected = False
|
||||
self._genesis_ready = False
|
||||
|
||||
print("INFO: Genesis microscope disconnected")
|
||||
return True
|
||||
|
||||
def apply_genesis_settings(self, settings: Dict) -> bool:
|
||||
"""
|
||||
Apply Genesis configuration settings
|
||||
|
||||
Args:
|
||||
settings: Dictionary containing Genesis parameters
|
||||
|
||||
Returns:
|
||||
bool: True if settings applied successfully
|
||||
"""
|
||||
print("DEBUG: Applying Genesis settings")
|
||||
print(f" Power: {settings.get('power_mw', 0)} mW")
|
||||
|
||||
if not self._genesis_connected:
|
||||
print("ERROR: Genesis not connected")
|
||||
return False
|
||||
|
||||
self._genesis_power_mw = settings.get('power_mw', 0.0)
|
||||
|
||||
# Stub - would send commands to actual hardware
|
||||
time.sleep(0.05)
|
||||
|
||||
print("INFO: Genesis settings applied")
|
||||
return True
|
||||
|
||||
def get_genesis_status(self) -> Dict[str, any]:
|
||||
"""
|
||||
Get Genesis microscope status
|
||||
|
||||
Returns:
|
||||
dict: Genesis status information
|
||||
"""
|
||||
return {
|
||||
'connected': self._genesis_connected,
|
||||
'ready': self._genesis_ready,
|
||||
'interlocked': self._genesis_interlocked,
|
||||
'power_mw': self._genesis_power_mw
|
||||
}
|
||||
|
||||
# ==================== Helios Methods ====================
|
||||
|
||||
def connect_helios(self, port: str) -> bool:
|
||||
"""
|
||||
Connect to Helios laser system
|
||||
|
||||
Args:
|
||||
port: COM port for Helios device
|
||||
|
||||
Returns:
|
||||
bool: True if connection successful
|
||||
"""
|
||||
print(f"DEBUG: Connecting to Helios on {port}")
|
||||
|
||||
if not self._helios_driver.connect(port):
|
||||
return False
|
||||
|
||||
self._helios_port = port
|
||||
print(f"INFO: Helios connected on {port}")
|
||||
print(f" Controller S/N: {self._helios_driver.get_controller_serial()}")
|
||||
print(f" Head S/N: {self._helios_driver.get_head_serial()}")
|
||||
return True
|
||||
|
||||
def disconnect_helios(self) -> bool:
|
||||
"""
|
||||
Disconnect from Helios laser system
|
||||
|
||||
Returns:
|
||||
bool: True if disconnection successful
|
||||
"""
|
||||
print("DEBUG: Disconnecting from Helios")
|
||||
return self._helios_driver.disconnect()
|
||||
|
||||
def is_helios_connected(self) -> bool:
|
||||
"""Check if Helios is connected"""
|
||||
return self._helios_driver.is_connected()
|
||||
|
||||
def apply_helios_settings(self, settings: Dict) -> bool:
|
||||
"""
|
||||
Apply Helios configuration settings
|
||||
|
||||
This method connects and configures the Helios laser with the
|
||||
specified parameters from the settings dialog.
|
||||
|
||||
Args:
|
||||
settings: Dictionary containing:
|
||||
- com_port: COM port name
|
||||
- frequency_hz: Laser frequency in Hz
|
||||
- current_ma: Laser diode current in mA
|
||||
|
||||
Returns:
|
||||
bool: True if settings applied successfully
|
||||
"""
|
||||
if settings is None:
|
||||
print("ERROR: No settings provided")
|
||||
return False
|
||||
|
||||
print("DEBUG: Applying Helios settings")
|
||||
print(f" Port: {settings.get('com_port', 'N/A')}")
|
||||
print(f" Frequency: {settings.get('frequency_hz', 0)} Hz")
|
||||
print(f" Current: {settings.get('current_ma', 0)} mA")
|
||||
|
||||
# Connect if not already connected or port changed
|
||||
port = settings.get('com_port')
|
||||
if not port:
|
||||
print("ERROR: No COM port specified")
|
||||
return False
|
||||
|
||||
if not self.is_helios_connected() or port != self._helios_port:
|
||||
if self.is_helios_connected():
|
||||
self.disconnect_helios()
|
||||
if not self.connect_helios(port):
|
||||
return False
|
||||
|
||||
# Set frequency
|
||||
freq_hz = settings.get('frequency_hz', 0.0)
|
||||
if freq_hz > 0:
|
||||
if not self._helios_driver.set_frequency_hz(freq_hz):
|
||||
print("ERROR: Failed to set frequency")
|
||||
return False
|
||||
time.sleep(0.05)
|
||||
|
||||
# Set current
|
||||
current_ma = settings.get('current_ma', 0.0)
|
||||
if current_ma > 0:
|
||||
if not self._helios_driver.set_current_ma(current_ma):
|
||||
print("ERROR: Failed to set current")
|
||||
return False
|
||||
time.sleep(0.05)
|
||||
|
||||
# Set to continuous pulsing mode by default
|
||||
if not self._helios_driver.set_pulse_mode(PulseMode.CONTINUOUS_PULSING):
|
||||
print("WARNING: Failed to set pulse mode")
|
||||
|
||||
print("INFO: Helios settings applied successfully")
|
||||
return True
|
||||
|
||||
def helios_enable_laser(self, enabled: bool) -> bool:
|
||||
"""
|
||||
Enable or disable Helios laser
|
||||
|
||||
Args:
|
||||
enabled: True to enable, False to disable
|
||||
|
||||
Returns:
|
||||
bool: True if command successful
|
||||
"""
|
||||
if not self.is_helios_connected():
|
||||
print("ERROR: Helios not connected")
|
||||
return False
|
||||
|
||||
return self._helios_driver.set_laser_enable(enabled)
|
||||
|
||||
def is_helios_laser_enabled(self) -> bool:
|
||||
"""Check if Helios laser is currently enabled"""
|
||||
if not self.is_helios_connected():
|
||||
return False
|
||||
return self._helios_driver.is_laser_enabled()
|
||||
|
||||
def get_helios_status(self) -> Dict[str, any]:
|
||||
"""
|
||||
Get Helios laser system status
|
||||
|
||||
Returns:
|
||||
dict: Helios status information
|
||||
"""
|
||||
if not self.is_helios_connected():
|
||||
return {
|
||||
'connected': False,
|
||||
'ready': False,
|
||||
'interlocked': False,
|
||||
'port': None,
|
||||
'frequency_hz': 0.0,
|
||||
'current_ma': 0.0,
|
||||
'laser_enabled': False,
|
||||
'power_mw': 0.0
|
||||
}
|
||||
|
||||
# Get comprehensive status from driver
|
||||
status = self._helios_driver.get_status()
|
||||
|
||||
return {
|
||||
'connected': status['connected'],
|
||||
'ready': not status['has_errors'],
|
||||
'interlocked': not status['has_errors'], # Use error state as interlock
|
||||
'port': self._helios_port,
|
||||
'frequency_hz': status['frequency_hz'],
|
||||
'current_ma': status['current_ma'],
|
||||
'laser_enabled': status['laser_enabled'],
|
||||
'power_mw': status['power_mw'],
|
||||
'operation_hours': status['operation_hours'],
|
||||
'controller_serial': status['controller_serial'],
|
||||
'head_serial': status['head_serial']
|
||||
}
|
||||
|
||||
def helios_update_status(self):
|
||||
"""Update Helios status from hardware"""
|
||||
if self.is_helios_connected():
|
||||
self._helios_driver.update_status()
|
||||
|
||||
# ==================== Combined Status Methods ====================
|
||||
|
||||
def get_status(self) -> Dict[str, any]:
|
||||
"""
|
||||
Get complete microscope system status
|
||||
|
||||
Returns:
|
||||
dict: Combined status for Genesis, Helios, and interlocks
|
||||
"""
|
||||
# Get Helios status from driver
|
||||
helios_status = self.get_helios_status()
|
||||
helios_ready = helios_status.get('ready', False)
|
||||
helios_interlocked = helios_status.get('interlocked', False)
|
||||
|
||||
return {
|
||||
# System-wide
|
||||
'interlocked': self._system_interlocked or (
|
||||
self._genesis_interlocked and helios_interlocked
|
||||
),
|
||||
|
||||
# Genesis
|
||||
'genesis_ready': self._genesis_ready,
|
||||
'genesis_interlocked': self._genesis_interlocked,
|
||||
|
||||
# Helios
|
||||
'helios_ready': helios_ready,
|
||||
'helios_interlocked': helios_interlocked
|
||||
}
|
||||
|
||||
def check_interlocks(self) -> bool:
|
||||
"""
|
||||
Check all safety interlocks
|
||||
|
||||
Returns:
|
||||
bool: True if all interlocks are satisfied
|
||||
"""
|
||||
# Check Genesis interlocks
|
||||
if self._genesis_connected and not self._genesis_interlocked:
|
||||
print("WARNING: Genesis interlock not satisfied")
|
||||
return False
|
||||
|
||||
# Check Helios interlocks
|
||||
if self.is_helios_connected():
|
||||
helios_status = self.get_helios_status()
|
||||
if not helios_status.get('interlocked', False):
|
||||
print("WARNING: Helios interlock not satisfied")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# ==================== Scan Preparation ====================
|
||||
|
||||
def prepare_for_scan(self, params: Dict) -> bool:
|
||||
"""
|
||||
Prepare microscope systems for scanning
|
||||
|
||||
Args:
|
||||
params: Scan parameters dictionary
|
||||
|
||||
Returns:
|
||||
bool: True if preparation successful
|
||||
"""
|
||||
print("DEBUG: Preparing microscope systems for scan")
|
||||
|
||||
# Check interlocks
|
||||
if not self.check_interlocks():
|
||||
print("ERROR: Interlock check failed")
|
||||
return False
|
||||
|
||||
# Verify systems are ready
|
||||
if self._genesis_connected and not self._genesis_ready:
|
||||
print("ERROR: Genesis not ready")
|
||||
return False
|
||||
|
||||
if self.is_helios_connected():
|
||||
helios_status = self.get_helios_status()
|
||||
if not helios_status.get('ready', False):
|
||||
print("ERROR: Helios not ready")
|
||||
return False
|
||||
|
||||
# Configure for scan
|
||||
# Stub implementation
|
||||
time.sleep(0.1)
|
||||
|
||||
print("INFO: Microscope systems ready for scan")
|
||||
return True
|
||||
|
||||
def emergency_stop(self) -> bool:
|
||||
"""
|
||||
Emergency stop all microscope operations
|
||||
|
||||
Returns:
|
||||
bool: True if stop successful
|
||||
"""
|
||||
print("WARNING: Emergency stop triggered")
|
||||
|
||||
# Disable all systems
|
||||
if self._genesis_connected:
|
||||
self._genesis_ready = False
|
||||
|
||||
if self.is_helios_connected():
|
||||
# Disable Helios laser immediately
|
||||
self._helios_driver.set_laser_enable(False)
|
||||
|
||||
return True
|
||||
Reference in New Issue
Block a user