# Copyright (c) ETH Zurich, SIS ID and HVL D-ITET
#
"""
Constants, ValueEnum: MeasurementFunction and TriggerSoruce
Descriptors for range, filter and aperture
"""
import logging
from hvl_ccb.dev import DeviceError
from hvl_ccb.dev.fluke884x.ranges import (
ACCurrentRange,
ACVoltageRange,
ApertureRange,
DCCurrentRange,
DCVoltageRange,
FilterRange,
ResistanceRange,
)
from hvl_ccb.utils.enum import ValueEnum
from hvl_ccb.utils.validation import validate_number
logger = logging.getLogger(__name__)
[docs]
class Fluke8845aError(DeviceError):
pass
[docs]
class Fluke8845aCheckError(Fluke8845aError):
pass
[docs]
class Fluke8845aUnknownCommandError(Fluke8845aError):
pass
[docs]
class MeasurementFunction(ValueEnum):
"""
Page 40
Sets the Meter function. This command must be followed by the INIT and FETCh?
commands to cause the meter to take a measurement.
"""
CURRENT_AC = "CURR:AC"
CURRENT_DC = "CURR"
VOLTAGE_AC = "VOLT:AC"
VOLTAGE_DC = "VOLT"
FOUR_WIRE_RESISTANCE = "FRES"
TWO_WIRE_RESISTANCE = "RES"
FREQUENCY = "FREQ"
PERIOD = "PER"
DIODE = "DIOD"
def _range(self):
if self == MeasurementFunction.VOLTAGE_AC:
return ACVoltageRange
elif self == MeasurementFunction.VOLTAGE_DC:
return DCVoltageRange
elif self == MeasurementFunction.CURRENT_AC:
return ACCurrentRange
elif self == MeasurementFunction.CURRENT_DC:
return DCCurrentRange
elif self in (
MeasurementFunction.TWO_WIRE_RESISTANCE,
MeasurementFunction.FOUR_WIRE_RESISTANCE,
):
return ResistanceRange
def _filter(self):
if self in (MeasurementFunction.VOLTAGE_AC, MeasurementFunction.CURRENT_AC):
return FilterRange
def _aperture(self):
if self in (MeasurementFunction.FREQUENCY, MeasurementFunction.PERIOD):
return ApertureRange
[docs]
class TriggerSource(ValueEnum):
"""
Page 57
.. code-block:: rst
BUS: Sets the Meter to expect a trigger through the IEEE-488 bus or
upon execution of a *TRG command
IMM: Selects Meter's internal triggering system
EXT: Sets the Meter to sense triggers through the trigger jack on the rear
panel of the Meter
"""
BUS = "BUS"
IMMEDIATE = "IMM"
EXTERNAL = "EXT"
class _BaseDescriptor:
def __init__(self, cmd_enum):
self._cmd_enum = cmd_enum
self._query_cmd = None
self._write_cmd = None
self._range_enum = None
self._value_min = None
self._value_max = None
def __get__(self, instance, owner=None):
voltage_range = float(instance.com.query(self._query_cmd))
return self._range_enum(voltage_range)
def __set__(self, instance, input_range):
if not isinstance(input_range, self._range_enum):
validate_number(
"input range",
input_range,
(self._value_min, self._value_max),
logger=logger,
)
input_range = self._range_enum(input_range)
instance.com.write(f"{self._write_cmd} {input_range}")
if self.__get__(instance) == float(input_range.value):
logger.info(
f"{self._write_cmd} is successfully set "
f"to {input_range} {self._range_enum.unit()}."
)
else:
msg = f"{self._cmd_enum} setting failed."
logger.error(msg)
raise Fluke8845aCheckError(msg)
class _RangeDescriptor(_BaseDescriptor):
def __init__(self, cmd_enum):
super().__init__(cmd_enum)
self._query_cmd = f"{self._cmd_enum}:RANG?"
self._write_cmd = f"{self._cmd_enum}:RANG"
self._range_enum = cmd_enum._range()
self._value_min = 0
self._value_max = max(self._range_enum)
def __set__(self, instance, input_range):
super().__set__(instance, input_range)
class _FilterDescriptor(_BaseDescriptor):
def __init__(self, cmd_enum):
super().__init__(cmd_enum)
self._query_cmd = f"{self._cmd_enum}:BAND?"
self._write_cmd = f"{self._cmd_enum}:BAND"
self._range_enum = cmd_enum._filter()
self._value_min = min(self._range_enum)
self._value_max = max(self._range_enum)
class _ApertureDescriptor(_BaseDescriptor):
def __init__(self, cmd_enum):
super().__init__(cmd_enum)
self._query_cmd = f"{self._cmd_enum}:APER?"
self._write_cmd = f"{self._cmd_enum}:APER"
self._range_enum = cmd_enum._aperture()
self._value_min = min(self._range_enum)
self._value_max = max(self._range_enum)