WIP: widget development #48

Draft
hitz_s wants to merge 2 commits from feat/widget-development into main
pull from: feat/widget-development
4 changed files with 542 additions and 0 deletions

No files matched your search

@@ -70,6 +70,36 @@ es1ic2_try:
enabled: true
softwareTrigger: false
ic0:
readoutPriority: baseline
description: Ionization chamber 0
deviceClass: superxas_bec.devices.ionization_chambers.ionization_chamber.IonizationChamber0
deviceConfig:
prefix: "X10DA-"
onFailure: retry
enabled: true
softwareTrigger: false
ic1:
readoutPriority: baseline
description: Ionization chamber 1
deviceClass: superxas_bec.devices.ionization_chambers.ionization_chamber.IonizationChamber1
deviceConfig:
prefix: "X10DA-"
onFailure: retry
enabled: true
softwareTrigger: false
ic2:
readoutPriority: baseline
description: Ionization chamber 2
deviceClass: superxas_bec.devices.ionization_chambers.ionization_chamber.IonizationChamber2
deviceConfig:
prefix: "X10DA-"
onFailure: retry
enabled: true
softwareTrigger: false
###################################
## Sample Manipulator ##
###################################
Whitespace-only changes.
@@ -0,0 +1,411 @@
"""Ionization chamber device class"""
from __future__ import annotations
from typing import TYPE_CHECKING, Literal
from bec_lib.logger import bec_logger
from ophyd import DynamicDeviceComponent as Dcpt
from ophyd import EpicsSignal, EpicsSignalRO
from ophyd_devices import CompareStatus
from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase
from superxas_bec.devices.ionization_chambers.ionization_chamber_enums import (
GAIN_MAP,
AmplifierBias,
AmplifierError,
AmplifierFilter,
AmplifierFilterAutoFilt,
AmplifierFilterStatus,
AmplifierGain10X,
AmplifierSuppr,
AmplifierZeroCheck,
)
if TYPE_CHECKING: # pragma: no cover
from bec_lib.devicemanager import ScanInfo
logger = bec_logger.logger
class IonizationChamberError(Exception):
"""Exception for the Ionization Chambers"""
class IonizationChamber0(PSIDeviceBase):
"""Ionization Chamber 0, prefix should be 'X10DA-'."""
USER_ACCESS = ["set_gain", "set_filter"]
num = 1
amp_signals = {
"cGain_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getGain",
"write_pv": f"ES-KEITH{num}:setGain",
"kind": "config",
"doc": f"Gain of Keithley {num} -> IC{num-1}",
},
),
"cGain10X_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getGain10X",
"write_pv": f"ES-KEITH{num}:setGain10X",
"kind": "config",
"doc": f"Gain 10x of Keithley {num} -> IC{num-1}",
},
),
"cFilterStatus_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getFilter",
"write_pv": f"ES-KEITH{num}:setFilter",
"kind": "config",
"doc": f"Filter Status of Keithley {num} -> IC{num-1}",
},
),
"cFilter_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getRiseTime",
"write_pv": f"ES-KEITH{num}:setRiseTime",
"kind": "config",
"doc": f"Filter of Keithley {num} -> IC{num-1}",
},
),
"cFilterAutoFilt_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getAutoFilt",
"write_pv": f"ES-KEITH{num}:setAutoFilt",
"kind": "config",
"doc": f"Filter Status of Keithley {num} -> IC{num-1}",
},
),
"cZeroCheck_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getZeroCheck",
"write_pv": f"ES-KEITH{num}:setZeroCheck",
"kind": "config",
"doc": f"ZeroCheck of Keithley {num} -> IC{num-1}",
},
),
"cBias_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getBias",
"write_pv": f"ES-KEITH{num}:setBias",
"kind": "config",
"doc": f"Bias of Keithley {num} -> IC{num-1}",
},
),
"cSuppr_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getSuppr",
"write_pv": f"ES-KEITH{num}:setSuppr",
"kind": "config",
"doc": f"Suppression of Keithley {num} -> IC{num-1}",
},
),
"cError_ENUM": (
EpicsSignalRO,
{
"read_pv": f"ES-KEITH{num}:getError",
"kind": "config",
"doc": f"Error of Keithley {num} -> IC{num-1}",
},
),
}
amp = Dcpt(amp_signals)
def __init__(self, name: str, prefix: str = "", scan_info: ScanInfo | None = None, **kwargs):
self.timeout_for_pvwait = 2.5
super().__init__(name=name, prefix=prefix, scan_info=scan_info, **kwargs)
def set_keithley(self) -> None:
"""Make sure Keithley is in a normal operation mode"""
status_list = []
if self.amp.cZeroCheck_ENUM.get() != AmplifierZeroCheck.OFF:
status_list.append(self.amp.cZeroCheck_ENUM.set(AmplifierZeroCheck.OFF))
if self.amp.cAutoFilt_Enum.get() != AmplifierFilterAutoFilt.MANUAL:
status_list.append(self.amp.cAutoFilt_Enum.set(AmplifierFilterAutoFilt.MANUAL))
if self.amp.cBias_ENUM.get() != AmplifierBias.OFF:
status_list.append(self.amp.cBias_ENUM.set(AmplifierBias.OFF))
if self.amp.cSuppr_ENUM.get() != AmplifierSuppr.OFF:
status_list.append(self.amp.cSuppr_ENUM.set(AmplifierSuppr.OFF))
for s in status_list:
s.wait(timeout=self.timeout_for_pvwait)
error = self.amp.cError_ENUM.get()
if error in [
AmplifierError.EEPROM_ERROR,
AmplifierError.INVALID_COMMAND,
AmplifierError.INVALID_OPTION,
AmplifierError.NOT_IN_REMOTE,
AmplifierError.SELFTEST_FAILED,
AmplifierError.SUPPR_CONFLICT,
AmplifierError.ZEROCHECK_ON,
AmplifierError.ZEROCORR_FAILED,
]:
raise IonizationChamberError(f"Keithley {self.num} error {AmplifierError(error)}")
def set_gain(self, gain: float) -> None:
"""Configure the gain setting of the specified channel
Args:
gain(float): Amplifier gain to set. Accepts either a float/int or a string,
e.g. 1e6 or "1e6". Must be one of: 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10.
Raises:
ValueError: If `gain` cannot be converted to a float, or does not
match one of the supported gain values.
"""
try:
key = float(gain)
except (TypeError, ValueError) as exc:
raise ValueError(f"Invalid gain: {gain!r}") from exc
try:
enum_val = GAIN_MAP[key]
except KeyError as exc:
raise ValueError(
f"Unsupported gain: {gain!r}. Must be one of {sorted(GAIN_MAP)}"
) from exc
self.set_keithley()
if self.amp.cGain10X_ENUM.get() != AmplifierGain10X.G1X:
logger.warning(
f"Keithley {self.num} was not in Gain10X == {AmplifierGain10X.G1X}, will try to set it to this value"
)
self.amp.cGain10X_ENUM.put(AmplifierGain10X.G1X)
status = CompareStatus(self.amp.cGain10X_ENUM, AmplifierGain10X.G1X)
status.wait(self.timeout_for_pvwait)
self.amp.cGain_ENUM.put(enum_val)
status = CompareStatus(self.amp.cGain_ENUM, enum_val)
status.wait(self.timeout_for_pvwait)
def set_filter(
self,
value: Literal[
"10us", "30us", "100us", "300us", "1ms", "3ms", "10ms", "30ms", "100ms", "300ms"
],
) -> None:
"""Configure the filter setting of the specified channel
Args:
value (Literal["10us", "30us", "100us", "300us", "1ms", "3ms", "10ms", "30ms", "100ms", "300ms"]) :Desired filter
"""
self.set_keithley()
if self.amp.cFilterStatus_ENUM.get() != AmplifierFilterStatus.ON:
logger.warning(f"Keithley {self.num} filter was switched off, switch it on now")
self.amp.cFilterStatus_ENUM.put(AmplifierFilterStatus.ON)
status = CompareStatus(self.amp.cFilterStatus_ENUM, AmplifierFilterStatus.ON)
status.wait(self.timeout_for_pvwait)
match value:
case "10us":
self.amp.cFilter_ENUM.put(AmplifierFilter.F10US)
case "30us":
self.amp.cFilter_ENUM.put(AmplifierFilter.F30US)
case "100us":
self.amp.cFilter_ENUM.put(AmplifierFilter.F100US)
case "300us":
self.amp.cFilter_ENUM.put(AmplifierFilter.F300US)
case "1ms":
self.amp.cFilter_ENUM.put(AmplifierFilter.F1MS)
case "3ms":
self.amp.cFilter_ENUM.put(AmplifierFilter.F3MS)
case "10ms":
self.amp.cFilter_ENUM.put(AmplifierFilter.F10MS)
case "30ms":
self.amp.cFilter_ENUM.put(AmplifierFilter.F30MS)
case "100ms":
self.amp.cFilter_ENUM.put(AmplifierFilter.F100MS)
case "300ms":
self.amp.cFilter_ENUM.put(AmplifierFilter.F300MS)
class IonizationChamber1(IonizationChamber0):
"""Ionization Chamber 1, prefix should be 'X10DA-'."""
num = 2
amp_signals = {
"cGain_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getGain",
"write_pv": f"ES-KEITH{num}:setGain",
"kind": "config",
"doc": f"Gain of Keithley {num} -> IC{num-1}",
},
),
"cGain10X_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getGain10X",
"write_pv": f"ES-KEITH{num}:setGain10X",
"kind": "config",
"doc": f"Gain 10x of Keithley {num} -> IC{num-1}",
},
),
"cFilterStatus_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getFilter",
"write_pv": f"ES-KEITH{num}:setFilter",
"kind": "config",
"doc": f"Filter Status of Keithley {num} -> IC{num-1}",
},
),
"cFilter_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getRiseTime",
"write_pv": f"ES-KEITH{num}:setRiseTime",
"kind": "config",
"doc": f"Filter of Keithley {num} -> IC{num-1}",
},
),
"cFilterAutoFilt_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getAutoFilt",
"write_pv": f"ES-KEITH{num}:setAutoFilt",
"kind": "config",
"doc": f"Filter Status of Keithley {num} -> IC{num-1}",
},
),
"cZeroCheck_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getZeroCheck",
"write_pv": f"ES-KEITH{num}:setZeroCheck",
"kind": "config",
"doc": f"ZeroCheck of Keithley {num} -> IC{num-1}",
},
),
"cBias_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getBias",
"write_pv": f"ES-KEITH{num}:setBias",
"kind": "config",
"doc": f"Bias of Keithley {num} -> IC{num-1}",
},
),
"cSuppr_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getSuppr",
"write_pv": f"ES-KEITH{num}:setSuppr",
"kind": "config",
"doc": f"Suppression of Keithley {num} -> IC{num-1}",
},
),
"cError_ENUM": (
EpicsSignalRO,
{
"read_pv": f"ES-KEITH{num}:getError",
"kind": "config",
"doc": f"Error of Keithley {num} -> IC{num-1}",
},
),
}
amp = Dcpt(amp_signals)
class IonizationChamber2(IonizationChamber0):
"""Ionization Chamber 2, prefix should be 'X10DA-'."""
num = 3
amp_signals = {
"cGain_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getGain",
"write_pv": f"ES-KEITH{num}:setGain",
"kind": "config",
"doc": f"Gain of Keithley {num} -> IC{num-1}",
},
),
"cGain10X_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getGain10X",
"write_pv": f"ES-KEITH{num}:setGain10X",
"kind": "config",
"doc": f"Gain 10x of Keithley {num} -> IC{num-1}",
},
),
"cFilterStatus_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getFilter",
"write_pv": f"ES-KEITH{num}:setFilter",
"kind": "config",
"doc": f"Filter Status of Keithley {num} -> IC{num-1}",
},
),
"cFilter_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getRiseTime",
"write_pv": f"ES-KEITH{num}:setRiseTime",
"kind": "config",
"doc": f"Filter of Keithley {num} -> IC{num-1}",
},
),
"cFilterAutoFilt_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getAutoFilt",
"write_pv": f"ES-KEITH{num}:setAutoFilt",
"kind": "config",
"doc": f"Filter Status of Keithley {num} -> IC{num-1}",f"ES-KEITH{num}:
},
),
"cZeroCheck_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getZeroCheck",
"write_pv": f"ES-KEITH{num}:setZeroCheck",
"kind": "config",
"doc": f"ZeroCheck of Keithley {num} -> IC{num-1}",
},
),
"cBias_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getBias",
"write_pv": f"ES-KEITH{num}:setBias",
"kind": "config",
"doc": f"Bias of Keithley {num} -> IC{num-1}",
},
),
"cSuppr_ENUM": (
EpicsSignal,
{
"read_pv": f"ES-KEITH{num}:getSuppr",
"write_pv": f"ES-KEITH{num}:setSuppr",
"kind": "config",
"doc": f"Suppression of Keithley {num} -> IC{num-1}",
},
),
"cError_ENUM": (
EpicsSignalRO,
{
"read_pv": f"ES-KEITH{num}:getError",
"kind": "config",
"doc": f"Error of Keithley {num} -> IC{num-1}",
},
),
}
amp = Dcpt(amp_signals)
@@ -0,0 +1,101 @@
import enum
class AmplifierGain(int, enum.Enum):
"""Enum class for the gain of the channel"""
G1E3 = 0
G1E4 = 1
G1E5 = 2
G1E6 = 3
G1E7 = 4
G1E8 = 5
G1E9 = 6
G1E10 = 7
GAIN_MAP = {
1e3: AmplifierGain.G1E3,
1e4: AmplifierGain.G1E4,
1e5: AmplifierGain.G1E5,
1e6: AmplifierGain.G1E6,
1e7: AmplifierGain.G1E7,
1e8: AmplifierGain.G1E8,
1e9: AmplifierGain.G1E9,
1e10: AmplifierGain.G1E10,
}
class AmplifierGain10X(int, enum.Enum):
"""Enum class for the 10X gain selection"""
G1X = 0
G10X = 1
class AmplifierFilter(int, enum.Enum):
"""Enum class for the filter of the channel"""
F10US = 0
F30US = 1
F100US = 2
F300US = 3
F1MS = 4
F3MS = 5
F10MS = 6
F30MS = 7
F100MS = 8
F300MS = 9
class AmplifierFilterStatus(int, enum.Enum):
"""Enum class for the filter status"""
OFF = 0
ON = 1
class AmplifierFilterAutoFilt(int, enum.Enum):
"""Enum class for the filter auto filt functionality"""
MANUAL = 0
AUTO = 1
class AmplifierZeroCheck(int, enum.Enum):
"""Enum class for the zero check"""
OFF = 0
ON = 1
AUTO = 2
class AmplifierBias(int, enum.Enum):
"""Enum class for the bias"""
OFF = 0
ON = 1
class AmplifierSuppr(int, enum.Enum):
"""Enum class for the suppression"""
OFF = 0
ON = 1
class AmplifierError(int, enum.Enum):
"""Enum class for amplifier errors"""
OK = 0
GAIN_CONFLICT = 1
OVERLOAD = 2
EEPROM_ERROR = 3
ZEROCORR_FAILED = 4
ZEROCHECK_ON = 5
INPUT_TOO_LARGE = 6
SUPPR_CONFLICT = 7
SELFTEST_FAILED = 8
NOT_IN_REMOTE = 9
INVALID_OPTION = 10
INVALID_COMMAND = 11