116 lines
3.7 KiB
Python
116 lines
3.7 KiB
Python
"""
|
|
Custom exceptions for laser control module.
|
|
|
|
Provides a hierarchy of exceptions for different error conditions
|
|
that may occur during laser control operations.
|
|
"""
|
|
|
|
|
|
class LaserControlError(Exception):
|
|
"""Base exception for all laser control errors."""
|
|
pass
|
|
|
|
|
|
class ValidationError(LaserControlError):
|
|
"""Base exception for validation errors."""
|
|
pass
|
|
|
|
|
|
class TemperatureOutOfRangeError(ValidationError):
|
|
"""Exception raised when temperature is outside valid range."""
|
|
|
|
def __init__(self, param_name: str, value: float, min_val: float, max_val: float):
|
|
self.param_name = param_name
|
|
self.value = value
|
|
self.min_val = min_val
|
|
self.max_val = max_val
|
|
super().__init__(
|
|
f"{param_name}: Temperature {value}°C is out of range "
|
|
f"[{min_val}°C - {max_val}°C]"
|
|
)
|
|
|
|
|
|
class CurrentOutOfRangeError(ValidationError):
|
|
"""Exception raised when current is outside valid range."""
|
|
|
|
def __init__(self, param_name: str, value: float, min_val: float, max_val: float):
|
|
self.param_name = param_name
|
|
self.value = value
|
|
self.min_val = min_val
|
|
self.max_val = max_val
|
|
super().__init__(
|
|
f"{param_name}: Current {value}mA is out of range "
|
|
f"[{min_val}mA - {max_val}mA]"
|
|
)
|
|
|
|
|
|
class InvalidParameterError(ValidationError):
|
|
"""Exception raised for invalid parameter types or values."""
|
|
|
|
def __init__(self, param_name: str, message: str):
|
|
self.param_name = param_name
|
|
super().__init__(f"{param_name}: {message}")
|
|
|
|
|
|
class CommunicationError(LaserControlError):
|
|
"""Base exception for communication errors."""
|
|
pass
|
|
|
|
|
|
class PortNotFoundError(CommunicationError):
|
|
"""Exception raised when serial port cannot be found."""
|
|
|
|
def __init__(self, port: str | None = None):
|
|
if port:
|
|
message = f"Serial port '{port}' not found"
|
|
else:
|
|
message = "No suitable serial port found for device connection"
|
|
super().__init__(message)
|
|
|
|
|
|
class PortBusyError(CommunicationError):
|
|
"""Raised when the serial port is already held by another program.
|
|
|
|
A laser controller is a single half-duplex request/response bus: only one
|
|
process may own it at a time. When the port is opened exclusively
|
|
(``exclusive=True``), a second exclusive open fails with this error instead
|
|
of silently sharing the bus and corrupting both sides' traffic.
|
|
"""
|
|
|
|
def __init__(self, port: str | None = None):
|
|
target = f"'{port}'" if port else "the laser controller port"
|
|
super().__init__(
|
|
f"Serial port {target} is busy — another program is already using "
|
|
f"the laser controller. Close it first (only one program may own the "
|
|
f"port at a time)."
|
|
)
|
|
|
|
|
|
class DeviceNotRespondingError(CommunicationError):
|
|
"""Exception raised when device doesn't respond to commands."""
|
|
|
|
def __init__(self, timeout: float | None = None):
|
|
if timeout:
|
|
message = f"Device did not respond within {timeout} seconds"
|
|
else:
|
|
message = "Device is not responding to commands"
|
|
super().__init__(message)
|
|
|
|
|
|
class CRCError(CommunicationError):
|
|
"""Exception raised when CRC check fails."""
|
|
|
|
def __init__(self, expected: int | None = None, received: int | None = None):
|
|
if expected is not None and received is not None:
|
|
message = f"CRC check failed. Expected: 0x{expected:04X}, Received: 0x{received:04X}"
|
|
else:
|
|
message = "CRC check failed on received data"
|
|
super().__init__(message)
|
|
|
|
|
|
class ProtocolError(CommunicationError):
|
|
"""Exception raised for protocol-level errors."""
|
|
|
|
def __init__(self, message: str):
|
|
super().__init__(f"Protocol error: {message}")
|