363 lines
11 KiB
Python
363 lines
11 KiB
Python
"""Instrument interface protocols.
|
|
|
|
This module defines the Hardware Abstraction Layer (HAL) interfaces for all
|
|
laboratory instruments used in DVT testing. These protocols allow test code
|
|
to be written against abstract interfaces rather than concrete implementations,
|
|
enabling seamless switching between simulated and real hardware.
|
|
|
|
The interfaces use ABC (Abstract Base Classes) for maximum type safety and
|
|
explicit interface implementation. All drivers must inherit from these base
|
|
classes and implement all abstract methods.
|
|
"""
|
|
|
|
from abc import ABC, abstractmethod
|
|
|
|
|
|
class IThermalChamber(ABC):
|
|
"""Hardware abstraction for thermal chambers.
|
|
|
|
Defines the interface for controlling environmental temperature during
|
|
thermal characterisation tests. Implementations may be virtual instruments
|
|
(simulators) or real hardware drivers.
|
|
|
|
Temperature units are always degrees Celsius.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def set_temperature(self, setpoint: float) -> None:
|
|
"""Set the chamber temperature setpoint.
|
|
|
|
Args:
|
|
setpoint: Target temperature in degrees Celsius.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If command fails or instrument reports error.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_temperature(self) -> float:
|
|
"""Get the actual chamber temperature.
|
|
|
|
Returns:
|
|
Current chamber air temperature in degrees Celsius.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_setpoint(self) -> float:
|
|
"""Get the current temperature setpoint.
|
|
|
|
Returns:
|
|
Current target temperature in degrees Celsius.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def is_stable(self) -> bool:
|
|
"""Check if chamber temperature is stable.
|
|
|
|
Temperature is considered stable when it has settled within
|
|
the instrument's configured stability threshold of the setpoint
|
|
for a minimum dwell time.
|
|
|
|
Returns:
|
|
True if temperature is stable, False if still settling.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def wait_until_stable(
|
|
self, timeout: float = 300.0, poll_interval: float = 1.0
|
|
) -> bool:
|
|
"""Wait until chamber temperature stabilises.
|
|
|
|
Polls the stability status at regular intervals until stable
|
|
or timeout is reached. This is a blocking call.
|
|
|
|
Args:
|
|
timeout: Maximum time to wait in seconds. Default 300s (5 minutes).
|
|
poll_interval: Time between stability checks in seconds. Default 1s.
|
|
|
|
Returns:
|
|
True if temperature stabilised within timeout, False if timed out.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If communication fails.
|
|
ValueError: If timeout or poll_interval are invalid.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def set_ramp_rate(self, rate: float) -> None:
|
|
"""Set the temperature ramp rate.
|
|
|
|
Controls how quickly the chamber changes temperature when moving
|
|
to a new setpoint. Slower ramp rates reduce thermal shock to DUT.
|
|
|
|
Args:
|
|
rate: Ramp rate in degrees Celsius per minute.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If command fails or instrument reports error.
|
|
ValueError: If rate is negative or exceeds instrument limits.
|
|
"""
|
|
pass
|
|
|
|
|
|
class IPowerSupply(ABC):
|
|
"""Hardware abstraction for programmable power supplies.
|
|
|
|
Defines the interface for controlling DC power supplies during electrical
|
|
characterisation tests. Implementations may be virtual instruments
|
|
(simulators) or real hardware drivers.
|
|
|
|
Voltage units are always volts (V).
|
|
Current units are always amps (A).
|
|
"""
|
|
|
|
@abstractmethod
|
|
def set_voltage(self, channel: int, voltage: float) -> None:
|
|
"""Set the output voltage setpoint.
|
|
|
|
Args:
|
|
channel: Output channel number (1-based indexing).
|
|
voltage: Target voltage in volts.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If command fails or instrument reports error.
|
|
ValueError: If channel is invalid or voltage out of range.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_voltage(self, channel: int) -> float:
|
|
"""Get the voltage setpoint.
|
|
|
|
Returns the programmed voltage, not the measured output voltage.
|
|
Use measure_voltage() to get the actual output voltage.
|
|
|
|
Args:
|
|
channel: Output channel number (1-based indexing).
|
|
|
|
Returns:
|
|
Current voltage setpoint in volts.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
ValueError: If channel is invalid.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def set_current_limit(self, channel: int, current: float) -> None:
|
|
"""Set the current limit.
|
|
|
|
The supply will operate in constant voltage mode until output current
|
|
reaches this limit, then transition to constant current mode.
|
|
|
|
Args:
|
|
channel: Output channel number (1-based indexing).
|
|
current: Current limit in amps.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If command fails or instrument reports error.
|
|
ValueError: If channel is invalid or current out of range.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_current_limit(self, channel: int) -> float:
|
|
"""Get the current limit.
|
|
|
|
Args:
|
|
channel: Output channel number (1-based indexing).
|
|
|
|
Returns:
|
|
Current limit in amps.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
ValueError: If channel is invalid.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def measure_voltage(self, channel: int) -> float:
|
|
"""Measure the actual output voltage.
|
|
|
|
Args:
|
|
channel: Output channel number (1-based indexing).
|
|
|
|
Returns:
|
|
Measured output voltage in volts.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
ValueError: If channel is invalid.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def measure_current(self, channel: int) -> float:
|
|
"""Measure the actual output current.
|
|
|
|
Args:
|
|
channel: Output channel number (1-based indexing).
|
|
|
|
Returns:
|
|
Measured output current in amps.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
ValueError: If channel is invalid.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def enable_output(self, channel: int, enable: bool) -> None:
|
|
"""Enable or disable the output.
|
|
|
|
Args:
|
|
channel: Output channel number (1-based indexing).
|
|
enable: True to enable output, False to disable.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If command fails or instrument reports error.
|
|
ValueError: If channel is invalid.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def is_output_enabled(self, channel: int) -> bool:
|
|
"""Check if output is enabled.
|
|
|
|
Args:
|
|
channel: Output channel number (1-based indexing).
|
|
|
|
Returns:
|
|
True if output is enabled, False if disabled.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
ValueError: If channel is invalid.
|
|
"""
|
|
pass
|
|
|
|
|
|
class IMultimeter(ABC):
|
|
"""Hardware abstraction for digital multimeters.
|
|
|
|
Defines the interface for making precision measurements with DMMs during
|
|
electrical characterisation tests. Implementations may be virtual instruments
|
|
(simulators) or real hardware drivers.
|
|
|
|
Voltage units are always volts (V).
|
|
Current units are always amps (A).
|
|
Resistance units are always ohms (Ω).
|
|
"""
|
|
|
|
@abstractmethod
|
|
def measure_dc_voltage(self, range: str = "AUTO") -> float:
|
|
"""Measure DC voltage.
|
|
|
|
Configures the meter for DC voltage and takes a measurement.
|
|
|
|
Args:
|
|
range: Measurement range. Default "AUTO" for auto-ranging.
|
|
Specific ranges depend on instrument capabilities.
|
|
|
|
Returns:
|
|
Measured voltage in volts.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
ValueError: If range is invalid for this instrument.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def measure_dc_current(self, range: str = "AUTO") -> float:
|
|
"""Measure DC current.
|
|
|
|
Configures the meter for DC current and takes a measurement.
|
|
|
|
Args:
|
|
range: Measurement range. Default "AUTO" for auto-ranging.
|
|
Specific ranges depend on instrument capabilities.
|
|
|
|
Returns:
|
|
Measured current in amps.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
ValueError: If range is invalid for this instrument.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def measure_resistance(self, range: str = "AUTO") -> float:
|
|
"""Measure resistance.
|
|
|
|
Configures the meter for resistance and takes a measurement.
|
|
|
|
Args:
|
|
range: Measurement range. Default "AUTO" for auto-ranging.
|
|
Specific ranges depend on instrument capabilities.
|
|
|
|
Returns:
|
|
Measured resistance in ohms.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If query fails or instrument reports error.
|
|
ValueError: If range is invalid for this instrument.
|
|
NotImplementedError: If instrument does not support resistance.
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def set_integration_time(self, nplc: float) -> None:
|
|
"""Set the integration time.
|
|
|
|
Integration time affects measurement accuracy and speed. Higher
|
|
values (more power line cycles) provide better noise rejection
|
|
but take longer to measure.
|
|
|
|
Args:
|
|
nplc: Integration time in number of power line cycles (NPLC).
|
|
Typical values: 0.02, 0.2, 1, 10, 100.
|
|
|
|
Raises:
|
|
ConnectionError: If not connected to instrument.
|
|
IOError: If command fails or instrument reports error.
|
|
ValueError: If nplc is invalid for this instrument.
|
|
NotImplementedError: If instrument does not support integration time.
|
|
"""
|
|
pass
|