134 lines
4.4 KiB
Python
134 lines
4.4 KiB
Python
"""Validation helpers for controller inputs."""
|
|
|
|
import math
|
|
import re
|
|
from typing import Any
|
|
|
|
from .constants import (
|
|
TEMP_MIN_C, TEMP_MAX_C,
|
|
CURRENT_MIN_MA, CURRENT_MAX_MA,
|
|
PROFILE_NAME_ALLOWED_PATTERN,
|
|
PROFILE_NAME_MAX_LENGTH,
|
|
)
|
|
from .exceptions import (
|
|
ValidationError,
|
|
TemperatureOutOfRangeError,
|
|
CurrentOutOfRangeError,
|
|
InvalidParameterError,
|
|
)
|
|
|
|
|
|
class ParameterValidator:
|
|
"""Validates all input parameters for the laser controller."""
|
|
|
|
@staticmethod
|
|
def _check_numeric(value: Any, param_name: str) -> float:
|
|
"""Check that value is a valid finite number. Returns float."""
|
|
if value is None:
|
|
raise InvalidParameterError(param_name, "Value must not be None")
|
|
if not isinstance(value, (int, float)):
|
|
raise InvalidParameterError(param_name, "Value must be a number")
|
|
if math.isnan(value):
|
|
raise InvalidParameterError(param_name, "Value must not be NaN")
|
|
if math.isinf(value):
|
|
raise InvalidParameterError(param_name, "Value must not be infinite")
|
|
return float(value)
|
|
|
|
@staticmethod
|
|
def validate_temperature(value: Any, param_name: str) -> float:
|
|
"""
|
|
Validate a laser temperature value.
|
|
|
|
Args:
|
|
value: Temperature in °C.
|
|
param_name: Parameter name for error messages.
|
|
|
|
Returns:
|
|
Validated temperature as float.
|
|
|
|
Raises:
|
|
InvalidParameterError: If value is not a valid number.
|
|
TemperatureOutOfRangeError: If value is outside [TEMP_MIN_C, TEMP_MAX_C].
|
|
"""
|
|
value = ParameterValidator._check_numeric(value, param_name)
|
|
if value < TEMP_MIN_C or value > TEMP_MAX_C:
|
|
raise TemperatureOutOfRangeError(
|
|
param_name, value, TEMP_MIN_C, TEMP_MAX_C
|
|
)
|
|
return value
|
|
|
|
@staticmethod
|
|
def validate_current(value: Any, param_name: str) -> float:
|
|
"""
|
|
Validate a laser drive current value.
|
|
|
|
Args:
|
|
value: Current in mA.
|
|
param_name: Parameter name for error messages.
|
|
|
|
Returns:
|
|
Validated current as float.
|
|
|
|
Raises:
|
|
InvalidParameterError: If value is not a valid number.
|
|
CurrentOutOfRangeError: If value is outside [CURRENT_MIN_MA, CURRENT_MAX_MA].
|
|
"""
|
|
value = ParameterValidator._check_numeric(value, param_name)
|
|
if value < CURRENT_MIN_MA or value > CURRENT_MAX_MA:
|
|
raise CurrentOutOfRangeError(
|
|
param_name, value, CURRENT_MIN_MA, CURRENT_MAX_MA
|
|
)
|
|
return value
|
|
|
|
@staticmethod
|
|
def validate_manual_mode_params(
|
|
temp1: Any,
|
|
temp2: Any,
|
|
current1: Any,
|
|
current2: Any,
|
|
) -> dict[str, float]:
|
|
"""
|
|
Validate all four manual mode parameters.
|
|
|
|
Args:
|
|
temp1: Laser 1 temperature, °C.
|
|
temp2: Laser 2 temperature, °C.
|
|
current1: Laser 1 current, mA.
|
|
current2: Laser 2 current, mA.
|
|
|
|
Returns:
|
|
Dict with validated floats: temp1, temp2, current1, current2.
|
|
|
|
Raises:
|
|
ValidationError: For any out-of-range value.
|
|
InvalidParameterError: For wrong types.
|
|
"""
|
|
return {
|
|
'temp1': ParameterValidator.validate_temperature(temp1, 'temp1'),
|
|
'temp2': ParameterValidator.validate_temperature(temp2, 'temp2'),
|
|
'current1': ParameterValidator.validate_current(current1, 'current1'),
|
|
'current2': ParameterValidator.validate_current(current2, 'current2'),
|
|
}
|
|
|
|
@staticmethod
|
|
def validate_profile_name(value: Any) -> str:
|
|
"""Validate a short ASCII profile name suitable for the device LCD."""
|
|
if not isinstance(value, str):
|
|
raise InvalidParameterError("profile_name", "Value must be a string")
|
|
|
|
normalized = value.strip()
|
|
if not normalized:
|
|
raise InvalidParameterError("profile_name", "Value must not be empty")
|
|
if len(normalized) > PROFILE_NAME_MAX_LENGTH:
|
|
raise InvalidParameterError(
|
|
"profile_name",
|
|
f"Value must be at most {PROFILE_NAME_MAX_LENGTH} characters long",
|
|
)
|
|
if re.fullmatch(PROFILE_NAME_ALLOWED_PATTERN, normalized) is None:
|
|
raise InvalidParameterError(
|
|
"profile_name",
|
|
"Only ASCII letters, digits, spaces, '-' and '_' are allowed",
|
|
)
|
|
|
|
return normalized
|